Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的な...

Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 / kaigionrails-2024-csrf

Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 の発表資料です

Takahiro Tsuchiya

October 25, 2024
Tweet

More Decks by Takahiro Tsuchiya

Other Decks in Programming

Transcript

  1. CSRF - Cross-Site Request Forgeries - クロスサイト・リクエスト・フォージェリ - しーさーふ -

    サイバー攻撃の一種 - 代表的な手口 - 既存のセッションを悪用して意図しない動作をさせる(Session Riding) - 今日はこのケースを前提として話す 4
  2. 6 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc Cookie: SESSION_ID=abc ヨシ!

    Cookieが自動送信されることに起因する攻撃 => APIモードでもCookie使うと対策が必要 ※Cookie以外でも発生するが今日は一旦忘れて説明する(Basic認証とか...) ヨシ! ※ログイン後(Cookieでのセッション確立後)だと思って見てください 悪意のあるサイトからも 勝手に送信されてしまう
  3. Railsはトークン方式で対策 - CSRFトークンを発行してチェックする - OWASP だと Synchronizer Token Pattern と呼ばれている

    - https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Preve ntion_Cheat_Sheet.html - フルスタックFWでよく見られる対策 - Laravel(PHP)も同様 7
  4. 10 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc (3) トークン送る (2)

    トークン表示 (1) トークンを発行 & セッションに紐づけて保存
  5. 11 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc (3) トークン送る トークン一致

    = 正規サイトだと判定して、 リクエストを許可する (2) トークン表示 (4) トークン検証 (1) トークンを発行 & セッションに紐づけて保存
  6. 12 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc Cookie: SESSION_ID=abc (3)

    トークン送る (2) トークン表示 (4) トークン検証 罠サイトからのリクエストは トークンが一致しないのでエラー (1) トークンを発行 & セッションに紐づけて保存
  7. 課題 - Rails API + SPA のプロダクト開発によく出会うようになった - Rails サーバーとは別に

    React 等でフロントエンドを別でホストするケース - 今の仕事もこれ - ※SPA = Single Page Application - CSRFトークンを使った対策をどう組み込むのがベストか分からない 15
  8. - ViewとControllerで数行書けば対策が終わる - これこそフルスタックの良さ - フロント・バックエンド双方が協調して成立するような防御手法を提供しやすい - Ruby on Rails

    Guides のようなドキュメントを提供しやすい(初学者にも優しい) Rails wayに乗っかる場合 16 View Rails Controller トークンの送信 csrf_meta_tags ヘルパの提供 トークンの生成 protect_from_forgery での検証 csrf_token
  9. - Rails wayから外れるのでトークン送受を自前で書くことになる - どう返して、どう管理して、どう渡す? - 公開されている事例も少ない Rails API +

    SPA の場合 17 View (SPA) Rails Controller protect_from_forgery での検証 ブラウザ Cookie: SESSION_ID= どうすれば?
  10. 方向性2: Cookieが自動で送られないようにする 23 ブラウザ API サーバー 正規サイト 罠サイト 自動送信される Cookie:

    SESSION_ID=abc Cookie: SESSION_ID=abc ↑自動で送られなければログイン扱いにならない
  11. 具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -

    より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 24
  12. 具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -

    より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 25
  13. Originヘッダー - ブラウザがリクエスト発生元をヘッダに付与して送信してくる - Origin は プロトコル x ホスト x

    ポート番号 で定義される - https://kaigionrails.org/2024/about であれば - https://kaigionrails.org 部分が Origin - 参考 - https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Origin - https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy 26
  14. 27 ブラウザ サーバー 正規サイト 罠サイト Origin: https://abunai-page.com 知らない!NG! リクエストの出どころを確認 =

    想定されるOriginのみ許可 Origin: https://app.example.com 想定してる!OK! https://abunai-page.com https://app.example.com シンプル!
  15. 昔は Form POST で送られなかった 30 送信方法 メソッド オリジン関係 ブラウザ 送信するようになった

    バージョン 備考 Form POST 同一オリジン Chrome系 v73 ?? 2019/03 リリース チケットの詳細確認できず Firefox v70 2019/10 リリース https://bugzilla.mozilla.org/show_bug.cgi?i d=1424076 Safari v11 ?? 2019/09 リリース チケットの詳細確認できず Edge (Legacy) v15 ?? 2017/04 リリース Edge Legacy自体が、 2021/03/09 サポート終了 現在ではすべてのブラウザの Form POST で Origin が送信される。 断片的な情報しかなく参考程度だが、5年前にはすべてのブラウザで対応が終わっている
  16. 補足資料: 同一オリジン・クロスオリジン 33 オリジンA オリジンB 同一?クロス? https://kaigionrails.com/ https://kaigionrails.com/2024 同一オリジン(パス違いはOK) http://kaigionrails.com

    クロスオリジン: プロトコルが異なる https://x.kaigionrails.com クロスオリジン: ホストが異なる https://kaigionrails.com:80 クロスオリジン: ポートが異なる
  17. 補足資料: 同一オリジン・クロスオリジン - クロスオリジンリクエスト - https://app.example.com/ (frontend) => https://api.example.com/ (API)

    - 同一オリジンリクエスト - https://app.example.com/ (frontend) => https://app.example.com/api/ (API) - Reverse Proxy を前段に配置するケースはこれ - https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Origin 34
  18. 具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -

    より安全に - リクエストの出どころを確認する - Fetch Metadata の確認(ココ) - Cookieが自動で送られないようにする - SameSite 属性の指定 35
  19. Sec-Fetch-Site - リクエスト発生元 - リクエスト先の関係性 - same-site, same-origin, cross-site, none

    が取りうる値 - 基本は same-site, same-origin を見れば防御できる - ざっくり - same-origin: オリジン完全一致 - same-site: サイト内(サブドメインはcross-originだがsame-site) - https://web.dev/articles/same-site-same-origin 37
  20. Sec-Fetch-Site のサポート状況 39 ブラウザ サポート開始 リリース日 備考 Chrome v76 2019/07/30

    Firefox v90 2021/07/13 Safari v16.4 2023/03/28 macOS Venture のサポート終了で非対応バージョンがなくなる。 正確に公表されてないが、 2027年あたり? Edge(Chromium) v79 2020/01/15 わりと新しい仕様なので、ヘッダがあればチェックする方針になりそう
  21. 具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -

    より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 40
  22. 41 ブラウザ API サーバー 正規サイト 罠サイト ブラウザが自動送信する Cookie: SESSION_ID=abc Cookie:

    SESSION_ID=abc ↑自動で送られないように設定したい Cookieが送信されないようにすれば良い
  23. SameSite属性の種類 - None - すべてのリクエストでCookie送信 - Lax - 同一サイトからのリクエスト -

    一部のクロスサイトリクエスト(トップレベル + GETメソッド)に対して送信される - Strict - 同一サイトからのリクエストのみ => Lax or Strictを指定すれば良い 43
  24. SameSiteのサポート状況 45 ブラウザ サポート開始 リリース日 デフォルト値の設定 リリース日 デフォルト値 Chrome v51

    2016/05 v80 2020/02 Lax Firefox v60 2018/05 2022年01に一度導入された がキャンセル None Safari v12 2018/09 - None Edge(Chromium) v79 2020/01 v80 2020/02 Lax 現行ブラウザはすべて対応しているが、デフォルトNoneのブラウザがある 明示的なLaxの指定が必要 参考 https://caniuse.com/?search=samesite
  25. 47

  26. 48

  27. 具体的な対策のまとめ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 => 基本的に送られてくるのでこれをメインでチェック

    - より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 => 存在すればチェック - Cookieが自動で送られないようにする - SameSite 属性の指定 => 抜け穴があるので他の対策と併用 51
  28. 補足: 先行発表事例 - 令和時代の API 実装のベースプラクティスと CSRF 対策 - https://blog.jxck.io/entries/2024-04-26/csrf.html

    - CSRF対策のやり方、そろそろアップデートしませんか - https://speakerdeck.com/hiro_y/update-your-knowledge-of-csrf-protection - PHPerKaigi 2024 53
  29. 補足: 他フレームワークの対策を調べた - Next.js - https://nextjs.org/blog/security-nextjs-server-components-actions - Hono - ディスカッションの内容が勉強になる

    - https://hono.dev/docs/middleware/builtin/csrf - https://github.com/honojs/hono/blob/main/src/middleware/csrf/index.ts - https://github.com/honojs/hono/issues/1688 - https://github.com/honojs/hono/pull/1760 54
  30. 発表後に聞かれた内容 - この対策は MPA(いわゆる普通のRails) でも有効? - 有効です。 - 課題の出発点が SPA

    + API であるだけで、MPAでも有効。 - MPA は Rails標準のCSRFトークンで保護できるので、触れなかった。 60