質問内容

最後に改めて記載しますが、最初に質問を記載します。

以下の2点について、ご教授いただきたいです。

  • そもそも実装方法が適切か
    • Gemを使うのがスタンダード、コードがおかしい、など
  • XSS脆弱性に対処できているか

やりたいこと

現在、Railsで掲示板を作成しています。

Twitterなど多くのサイトで使われているような、ユーザーが投稿するテキストにURLがある場合はtarget="_blank"を付けてリンク化して表示する機能を実装したいです。

また、テキスト内の改行を反映させたいため、Railsが用意しているビューヘルパーのsimple_formatを使用します。

実装に際して検索をかけてみたところ、以下の2つのGemが出てきたのですが、どちらのGemもネットに存在する情報が少ないことから、Gemを使った実装方法がスタンダードなのか分からないため、Gemを使わずに実装する形にしました。

  • tenderlove/rails_autolink

https://github.com/tenderlove/rails_autolink

  • vmg/rinku

https://github.com/vmg/rinku

参考にしたURL

以下が実装時に参考にしたURLです。

  • テキスト内のURLをリンク化して表示するため

[Ruby][Rails]テキスト内のURLをaタグに書き換える - Qiita

  • simple_formatをそのまま使用するとtarget="_blank"が消えるのに対処するため

ruby on rails - simple_format is stripping out target _blank - Stack Overflow

環境

Rails 5.0.0.1
Ruby 2.3.1

コード

以下で、ユーザーが投稿したテキストにURLが含まれていれば、その部分をリンクにするtext_url_to_linkメソッドを定義しています。

app/helpers/application_helper.rb

module ApplicationHelper
  require "uri"

  def text_url_to_link(text)
    URI.extract(text, ['http', 'https']).uniq.each do |url|
      sub_text = ""
      sub_text << "<a href=" << url << " target=\"_blank\">" << url << "</a>"
      text.gsub!(url, sub_text)
    end
    return text
  end
end

以下で、ユーザーが投稿したテキストを表示しています。

前提としまして、Discussionsテーブルにtext型のcontentカラムがある状況です。

質問したいコードをdivで囲ってidを設定しているのはAjaxでDiscussionのcontentを編集するためです。

app/views/discussions/index.html.erb

<% @discussions.each do |discussion| %>
  <div id="discussion-content-<%= discussion.id %>" class="discussion-content">
    <!-- 以下が質問をしたいコード -->
    <%= simple_format(text_url_to_link(h(discussion.content)), {}, sanitize: false) %>
  </div>
<% end %>

上記のviewファイル内の質問したいコードの流れは以下のようになっていると認識しています。

  • discussion.contentでユーザーが投稿したテキストを取得
  • hメソッドでタグをエスケープ
  • 自分で定義したtext_url_to_linkメソッドによりURL形式の文字列をaタグで囲む
  • simple_formatメソッドをそのまま使用すると、target="_blank"が効かなくなるので、オプションでsanitize: falseを指定
  • 最終的にテキスト内のURL形式の文字列がリンクで表示される

上記のコードを書いた状況で

<script>alert('hoge')</script>

と自分が作っている掲示板に投稿したところ、エスケープされて表示されました。

質問内容

改めて、質問内容を記載致します。以下の2点になります。

  • そもそも実装方法が適切か
    • Gemを使うのがスタンダード、コードがおかしい、など
  • XSS脆弱性に対処できているか

初心者のため、内容に至らない点もあるかもしれませんが、ご教授いただけますと幸いです。よろしくお願いいたします。