Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的な...
Search
Takahiro Tsuchiya
October 25, 2024
Programming
6
4.4k
Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 / kaigionrails-2024-csrf
Kaigi on Rails 2024 - Rails APIモードのためのシンプルで効果的なCSRF対策 の発表資料です
Takahiro Tsuchiya
October 25, 2024
Tweet
Share
More Decks by Takahiro Tsuchiya
See All by Takahiro Tsuchiya
現場のエンジニアから見た採用担当との協働
corocn
7
2.9k
シリーズAをリファラル採用中心に走り抜ける / leaner-referral-engineer-2024
corocn
3
1.8k
捨てて加速するプロダクト開発 / sutete-speedup-product-development
corocn
3
630
リファラル採用にフルベットしてみた
corocn
3
3.6k
エンジニアとプロダクトマネージャーを兼任した1年間を振り返る / pdm-furikaeri
corocn
17
7.6k
育休のすゝめ #devsumi 2023
corocn
3
4.7k
GCPでRubyを動かしている話 / ruby on gcp
corocn
0
900
フルリモートワーカーのデスク選定 / how-to-select-remote-work-desk
corocn
1
590
Auth0イントロダクション / corocn_auth0_day_recap_in_osaka
corocn
1
1k
Other Decks in Programming
See All in Programming
useSyncExternalStoreを使いまくる
ssssota
6
1k
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
5
900
rails stats で紐解く ANDPAD のイマを支える技術たち
andpad
1
290
Webエンジニア主体のモバイルチームの 生産性を高く保つためにやったこと
igreenwood
0
330
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
210
今年一番支援させていただいたのは認証系サービスでした
satoshi256kbyte
1
250
クリエイティブコーディングとRuby学習 / Creative Coding and Learning Ruby
chobishiba
0
3.9k
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
42 best practices for Symfony, a decade later
tucksaun
1
180
Recoilを剥がしている話
kirik
5
6.7k
range over funcの使い道と非同期N+1リゾルバーの夢 / about a range over func
mackee
0
110
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
540
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
40
7.1k
Writing Fast Ruby
sferik
628
61k
How to Ace a Technical Interview
jacobian
276
23k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
Visualization
eitanlees
146
15k
Being A Developer After 40
akosma
87
590k
The Language of Interfaces
destraynor
154
24k
Into the Great Unknown - MozCon
thekraken
33
1.5k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Embracing the Ebb and Flow
colly
84
4.5k
Making Projects Easy
brettharned
116
5.9k
Transcript
Rails APIモードのための シンプルで効果的なCSRF対策 2024/10/25-26 Kaigi on Rails 2024 株式会社Leaner Technologies
/ @corocn
2 @corocn / ころちゃん
まずは、おさらいから 3
CSRF - Cross-Site Request Forgeries - クロスサイト・リクエスト・フォージェリ - しーさーふ -
サイバー攻撃の一種 - 代表的な手口 - 既存のセッションを悪用して意図しない動作をさせる(Session Riding) - 今日はこのケースを前提として話す 4
5 ブラウザ サーバー 正規サイト 罠サイト リクエスト時に CookieでセッションIDが自動送信される Cookie: SESSION_ID=abc セッションチェック
ヨシ! ※ログイン後(Cookieでのセッション確立後)だと思って見てください
6 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc Cookie: SESSION_ID=abc ヨシ!
Cookieが自動送信されることに起因する攻撃 => APIモードでもCookie使うと対策が必要 ※Cookie以外でも発生するが今日は一旦忘れて説明する(Basic認証とか...) ヨシ! ※ログイン後(Cookieでのセッション確立後)だと思って見てください 悪意のあるサイトからも 勝手に送信されてしまう
Railsはトークン方式で対策 - CSRFトークンを発行してチェックする - OWASP だと Synchronizer Token Pattern と呼ばれている
- https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Preve ntion_Cheat_Sheet.html - フルスタックFWでよく見られる対策 - Laravel(PHP)も同様 7
8 ブラウザ サーバー 正規サイト 罠サイト (1) トークンを発行 & セッションに紐づけて保存
9 ブラウザ サーバー 正規サイト 罠サイト (2) トークン表示 (1) トークンを発行 &
セッションに紐づけて保存
10 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc (3) トークン送る (2)
トークン表示 (1) トークンを発行 & セッションに紐づけて保存
11 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc (3) トークン送る トークン一致
= 正規サイトだと判定して、 リクエストを許可する (2) トークン表示 (4) トークン検証 (1) トークンを発行 & セッションに紐づけて保存
12 ブラウザ サーバー 正規サイト 罠サイト Cookie: SESSION_ID=abc Cookie: SESSION_ID=abc (3)
トークン送る (2) トークン表示 (4) トークン検証 罠サイトからのリクエストは トークンが一致しないのでエラー (1) トークンを発行 & セッションに紐づけて保存
Railsはトークン方式で対策(実装) - 詳しくはRails セキュリティガイド(上記コードもこちらから引用) - https://railsguides.jp/security.html 13 View Controller
ここから本題 14
課題 - Rails API + SPA のプロダクト開発によく出会うようになった - Rails サーバーとは別に
React 等でフロントエンドを別でホストするケース - 今の仕事もこれ - ※SPA = Single Page Application - CSRFトークンを使った対策をどう組み込むのがベストか分からない 15
- ViewとControllerで数行書けば対策が終わる - これこそフルスタックの良さ - フロント・バックエンド双方が協調して成立するような防御手法を提供しやすい - Ruby on Rails
Guides のようなドキュメントを提供しやすい(初学者にも優しい) Rails wayに乗っかる場合 16 View Rails Controller トークンの送信 csrf_meta_tags ヘルパの提供 トークンの生成 protect_from_forgery での検証 csrf_token
- Rails wayから外れるのでトークン送受を自前で書くことになる - どう返して、どう管理して、どう渡す? - 公開されている事例も少ない Rails API +
SPA の場合 17 View (SPA) Rails Controller protect_from_forgery での検証 ブラウザ Cookie: SESSION_ID= どうすれば?
対策方法を考えよう - トークン方式にこだわりはない - 自分は標準機能にひっぱられる悪い癖があるので、フラットに考えよう - もっとシンプルに対策できる方法ない? 18
余談:「Rails SPA CSRF 対策」で調べると... - 検索すると私が3年前に書いた記事がヒットする - トークン方式を無理やり使う方法を解説している - もっとシンプルな方法あるよ!と伝えたいのも今日の発表のモチベ
19
対策 20
結局どうすれば対策できるの? - 方向性1: リクエストの出どころを確認する - 許可したサイトからのリクエストのみ受け入れる - 方向性2: Cookieが自動で送られないようにする -
悪意のあるサイトからCookieが自動で送られなければログイン状態にならない 21
方向性1: リクエストの出どころで判別する 22 ブラウザ サーバー 正規サイト 罠サイト このリクエスト元はOK! このリクエスト元はNG
方向性2: Cookieが自動で送られないようにする 23 ブラウザ API サーバー 正規サイト 罠サイト 自動送信される Cookie:
SESSION_ID=abc Cookie: SESSION_ID=abc ↑自動で送られなければログイン扱いにならない
具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -
より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 24
具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -
より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 25
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
27 ブラウザ サーバー 正規サイト 罠サイト Origin: https://abunai-page.com 知らない!NG! リクエストの出どころを確認 =
想定されるOriginのみ許可 Origin: https://app.example.com 想定してる!OK! https://abunai-page.com https://app.example.com シンプル!
ここで疑問 - Q. 既存の実装はなぜトークン方式なの? Originのがシンプルでは? 28
ここで疑問 - Q. 既存の実装はなぜトークン方式なの? Originのがシンプルでは? - A. ブラウザが Origin を送ってくれないケースがあったから
29
昔は 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年前にはすべてのブラウザで対応が終わっている
現在も送られないケース - GET | HEAD かつ 同一オリジン のとき - GETで副作用を発生させないよう作れば、このケースは無視できる
- 副作用が発生するメソッドでは Origin は送られてくると思って問題ない 31
補足資料: 例外も一応ある - https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Origin を見てね - 仮に送られなくても、リクエスト失敗(安全側に処理される)になるだけ 32
補足資料: 同一オリジン・クロスオリジン 33 オリジンA オリジンB 同一?クロス? https://kaigionrails.com/ https://kaigionrails.com/2024 同一オリジン(パス違いはOK) http://kaigionrails.com
クロスオリジン: プロトコルが異なる https://x.kaigionrails.com クロスオリジン: ホストが異なる https://kaigionrails.com:80 クロスオリジン: ポートが異なる
補足資料: 同一オリジン・クロスオリジン - クロスオリジンリクエスト - 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
具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -
より安全に - リクエストの出どころを確認する - Fetch Metadata の確認(ココ) - Cookieが自動で送られないようにする - SameSite 属性の指定 35
Fetch Metadata - 不正なリクエストを弾くための情報を提供するヘッダ - 4種類あるが Sec-Fetch-Site を使うのが良い - Sec-Fetch-Site
- Sec-Fetch-Dest - Sec-Fetch-Mode - Sec-Fetch-User 36
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
Fetch Metadata の良いところ - Originの使いにくい点を解消してくれる - Origin はそもそも付与されたり付与されなかったりするので複雑 - リクエストの文脈情報が提供されない
-> 詳細に提供してくれる - より強固なセキュリティポリシーに対応できる 38
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 わりと新しい仕様なので、ヘッダがあればチェックする方針になりそう
具体的なCSRF対策 3つ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 -
より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 - Cookieが自動で送られないようにする - SameSite 属性の指定 40
41 ブラウザ API サーバー 正規サイト 罠サイト ブラウザが自動送信する Cookie: SESSION_ID=abc Cookie:
SESSION_ID=abc ↑自動で送られないように設定したい Cookieが送信されないようにすれば良い
SameSite属性 - Cookieの属性 - クロスサイトでのCookie送信の挙動を制御するもの - 3rd Party Cookieの制御のための目的で作られた -
CSRF対策で使えるのはオマケ - 広告・プライバシー文脈のほうが強い 42
SameSite属性の種類 - None - すべてのリクエストでCookie送信 - Lax - 同一サイトからのリクエスト -
一部のクロスサイトリクエスト(トップレベル + GETメソッド)に対して送信される - Strict - 同一サイトからのリクエストのみ => Lax or Strictを指定すれば良い 43
SameSite属性 の2分ルール - SameSite=Laxの場合 - セットされた2分間はPOSTリクエストでもCookieが送信される - 古いシステムや特定のシナリオで必要になったり、 - ポータルからPOSTで別サービスでログインするようなケース。
- CSRF対策としては片手落ちになるので 他のチェックも併用 44
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
Railsでの実装 46
47
48
SameSite 指定 - config.action_dispatch.cookies_same_site_protection - 6.1以降はデフォルト Lax なので指定不要 - https://railsguides.jp/configuring.html
49
まとめ 50
具体的な対策のまとめ - 基本 - リクエストの出どころを確認する - Origin ヘッダーの確認 => 基本的に送られてくるのでこれをメインでチェック
- より安全に - リクエストの出どころを確認する - Fetch Metadata の確認 => 存在すればチェック - Cookieが自動で送られないようにする - SameSite 属性の指定 => 抜け穴があるので他の対策と併用 51
全体のまとめ - CSRF対策は「リクエストの出どころ」を確認することが大事 - RailsのViewを使う前提ならトークン方式を選べば良い - Rails API であれば Originチェックをベースラインとして考えよう
52
補足: 先行発表事例 - 令和時代の 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
補足: 他フレームワークの対策を調べた - 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
今日の発表者 - @corocn / ころちゃん - 岐阜から来ました - リーナーテクノロジーズ 所属
- nagara.rb 運営(”長良”川 の ながら) 55
56 Drinkup、当日空いたら是非・・・!
57 もうすぐ 1.0.0 = 開催100回
58 長良Ruby会議@岐阜をやるぞ! 来年の夏、鮎が美味しい時期あたり
ありがとうございました 59
発表後に聞かれた内容 - この対策は MPA(いわゆる普通のRails) でも有効? - 有効です。 - 課題の出発点が SPA
+ API であるだけで、MPAでも有効。 - MPA は Rails標準のCSRFトークンで保護できるので、触れなかった。 60