RailsのCSRF保護について

【結論】

CSRFとは、WEBアプリケーションの投稿機能などを利用して悪意のあるコードを仕込むことで、認証済みのユーザーに意図しないコマンドを実行させる攻撃手法

・対策は、GETとPOSTを適切に使い分け(RESTful)GET以外のリクエストにセキュリティトークンを追加すること

Railsでは、一意のトークンを生成し、フォームの送信時に照合することで攻撃を防ぐ仕組みがデフォルトで備わっている

【目次】

【本題】

CSRFについて

CSRFクロスサイトリクエストフォージェリ)とは、WEBアプリケーションの脆弱性を突いた攻撃手法です。

攻撃の方法としては、まずWEBアプリケーションに備わっている投稿機能などを用いて、悪意のあるコードをWEBページ上に仕込みます。

そして、第三者がコードの仕込まれたページを開くことで、意図しないリクエストが送信されます。

これにより、ユーザーのアカウント情報が無くとも、情報を抜き取ったり、金銭的な被害を与えることができます。

対策

対策は、GETとPOSTを適切に使い分け(RESTful)GET以外のリクエストにセキュリティトークンを追加することです。

GETとPOSTを適切に使い分け

HTTPメソッドのGETは、リソースの状態を変化させない特性を持っています。

リソースの取得はPOSTでも行えますが、POSTにはGETの様な安全性はありません。

その為、リソースの取得(データ読み込み、検索など)はGETを用います

GETであれば、意図せぬリクエストが送られたとしても、データが書きかえられたりする心配はありません。

GET以外のリクエストにセキュリティトークンを追加する

そして、GET以外のリクエストについては、セキュリティトークンを追加して対策をします。

具体的な流れとしては、以下の通りです。

  1. WEBページ(HTML)一意のトークンを埋め込む
  2. 同じトークンはセッションcookieにも保存する
  3. リクエストを送信するとき、HTMLのトークンも一緒に送信する
  4. 送られてきたトークンと、セッションのトークンを比較する
  5. 両方が一致すれば、リクエストを処理する
  6. 一致しなければ、リクエストをブロックする

これにより、意図しないリクエストによる攻撃を防ぐことができます。

RailsCSRF保護の仕組み

Railsには、このCSRF保護の仕組みがデフォルトで実装されています。

CSRF保護を有効にするには、以下のコードをapplication_controller.rbに記述します。

protect_from_forgery with: :exception

Rails5.1以前ではrails newの時点で既に記述されていますが、Rails5.2以降ではこのコードが無くとも設定が有効になっています。

HTMLにトークンを埋め込むコードは、以下の通りです。

<%= csrf_meta_tags %>

こちらもapplication.html.erbに標準で記述されています。

後は、form_withlink_to等のビューヘルパーを利用すれば、リクエスト送信時に勝手にトークンも送ってくれます。

これにより、トークンの生成→埋め込み/格納→送信→照合を全て行ってくれます。

Railsのフォーム以外の通信(Ajaxなど)でCSRF保護を利用する

なお、AjaxでPOST送信したい場合など、form_withlink_to等を使わない場合は、自分でトークンを送る必要があります。

JavaScriptでHTMLに埋め込まれたトークンを取得するには、以下の様にコードを実装すれば良いです。

const csrf_token = document.getElementsByName( 'csrf-token' ).item(0).content;

トークンは X-CSRF-Token というヘッダ名で受け取れます。

    $.ajaxPrefilter( (options, originalOptions, jqXHR) => {
        if (!options.crossDomain) {
          if (token) {
               return jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
           }
        }

なお、以下の様にパラメータで渡そうとすると、「+」がスペースに置換されてしまうので、一部でエラーが発生してしまうので注意が必要です。

$.ajax({
  data: "authenticity_token": csrf_token,
  type: "POST",
  url: "http://www.example.com/",
    // ...

参考情報

Rails セキュリティガイド - Railsガイド

RailsのCSRF保護を詳しく調べてみた(翻訳)|TechRacho by BPS株式会社

CSRFの対応について、rails使いが知っておくべきこと - おもしろwebサービス開発日記

外部からPOSTできない?RailsのCSRF対策をまとめてみた - Qiita

Rails アップグレードガイド - Railsガイド