Tech Racho エンジニアの「?」を「!」に。
  • 開発

[Rails 5] フォームごとに異なるCSRFトークンを受け取れるようになった(翻訳)

こんにちは、hachi8833です。
BigBinaryシリーズ、今回もRails 5から導入された機能についての翻訳記事をお届けいたします。

元記事

確認に使った環境

Rails 5の新機能: フォームごとに異なるCSRFトークンを受け取れるようになった(翻訳)

BigBinaryの以前の記事で、Rails 4でCSRF攻撃を防ぐための手順を詳しく紹介しました。本記事を詳しく理解するためにはこの記事もご覧ください。

Rails 4のCSRF保護は、ネストしたフォームで効かないことがある

Rails 4の典型的なフォームのコードを以下に示します(訳注: valueの< >はプレースホルダを表します)。

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="<token_value>">
</form>

攻撃者がコードを注入すると、RailsでJavaScriptを使って生成したフォームの外側に、以下のように別のフォームタグが追加される可能性があります。

<form method="post" action="http://www.fraud.com/fraud">
  <form method= "post" action="/money_transfer">
    <input type="hidden" name="authenticity_token" value="<token_value>">
  </form>
</form>

HTMLの仕様では、フォームのネストは許されていません

フォームのネストが禁止されているため、ブラウザは最も外側(最上位)のフォームのみを受け付けます。上のコードでは、攻撃者が捏造したフォームがネストの最上位に置かれています。このフォームが送信されると、内側にある「authenticity_token」も送信されます。Railsはこれを正当であると認識し、それによって攻撃者がサイトをハックできてしまいます。

Rails 5での修正: フォームでカスタムトークンを生成するようになった

Rails 5では、CSRFトークンをフォームごとに追加できるようになりました(#22275)。各CSRFトークンは、それを含むフォームに対応するメソッドやアクションに対してのみ有効になります。

コントローラに以下のようにself.per_form_csrf_tokens = trueを追加することで、コントローラのフォームタグごとにメソッドやアクション固有の認証トークンが追加されます。

class UsersController < ApplicationController
  self.per_form_csrf_tokens = true
end

このコードを各コントローラに追加して回るのは面倒なので、Railsの初期化設定に以下の記述を追加して、全コントローラで設定を有効にすることもできます。

# config/application.rb
Rails.configuration.action_controller.per_form_csrf_tokens = true

これにより、アプリケーションのフォームタグごとにメソッドやアクション固有の認証トークンが追加されます。トークンが追加された後のコードは以下のようになります。

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="<money_transfer_post_action_token>">
</form>

ここで使われている認証トークンは、money_transferアクションとpostメソッド固有です。攻撃者がこの認証トークンを取り出したとしても、攻撃はmoney_transferアクションへのpostのみに限定されます。

関連記事(Rail 5新機能)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。