Slide 1

Slide 1 text

2024年3月8日 / PHPerKaigi 2024 • Day 1 合同会社テンマド 山岡広幸 CSRF対策のやり方、 そろそろアップデートしませんか

Slide 2

Slide 2 text

自己紹介 - 山岡広幸(やまおかひろゆき) - Bluesky: @hiroy.kotori.style - X: @hiro_y - PHPは大学のころ、バージョンは3のころから - 最近はSvelteKitとかも

Slide 3

Slide 3 text

会社をやっています - 合同会社テンマド - 代表社員/2024年6月で10周年! - 現在のメンバーは総勢で5名 - PHPエンジニア採用募集中!!

Slide 4

Slide 4 text

お仕事先 - 株式会社イノベーター・ジャパン - 社外CTO/神宮前・柏・茅ヶ崎 - 株式会社GoQSystem - 技術顧問/京橋・岩国・広島 - 広島で勉強会やるぞ…!

Slide 5

Slide 5 text

さて、CSRF (発音: CSRF or “sea-surf")

Slide 6

Slide 6 text

Cross Site Request Forgery

Slide 7

Slide 7 text

Cross またいだ Site サイトを Request リクエストの Forgery 偽造行為

Slide 8

Slide 8 text

IPAによる情報提供 - 安全なウェブサイトの作り方 - 1.6 CSRF(クロスサイト・リクエスト・フォージェリ) - 共通脆弱性情報データベース - https://jvndb.jvn.jp/ja/cwe/CWE-352.html - 「脆弱なコード例」としてPHPのコードが載っている

Slide 9

Slide 9 text

CSRFの基本構造 出典: https://www.ipa.go.jp/security/vuln/websecurity/csrf.html

Slide 10

Slide 10 text

雑な解説 - 本来のサイトの正規ページを模倣した 悪意あるサイトの罠ページを用意 - 悪意あるサイトから本来のサイトに向けてリクエスト送信 - 意図しないパラメーターを含む等 攻撃的リクエスト(状態変更)を送ってしまう…

Slide 11

Slide 11 text

防御方法 1⃣ トークン

Slide 12

Slide 12 text

古来より伝わる防御方法 - サーバー側で予測不能な文字列(トークン)を生成、 セッションに保存し、トークンをフォームに埋め込み表示 - リクエストの際にトークンを含めるようにする - サーバー側でセッションで保持していたトークンと照合

Slide 13

Slide 13 text

つまりこう

Slide 14

Slide 14 text

Laravelの場合 - CSRF Protection - Laravel 10.x - Bladeテンプレートでは @csrf と書けばOK -

Slide 15

Slide 15 text

トークン方式のメリット - 確実に防御することができる - 数多くのフレームワークで採用されている - Symfony、Ruby on Rails、Play Framework等 - (フレームワークを使っていれば)お手軽に導入可能

Slide 16

Slide 16 text

トークン方式のデメリット - (よく考えると)シンプルな実装とは言いがたい - トークンを保管するストレージが必要 - セッション用Cookieを改竄されてしまうと… - (XSS等がある時点でCSRFどころではないのでは…

Slide 17

Slide 17 text

さて、最近の話

Slide 18

Slide 18 text

アップデート していきましょう!

Slide 19

Slide 19 text

このトークのきっかけ - SvelteKitを触っていた - あれ、CSRF対策とかどうするんだろう… hidden項目とか必要じゃないんだっけ?? - CookieのSameSite属性とかあったような… - よい機会なので調べてみよう!!

Slide 20

Slide 20 text

防御方法 2⃣ SameSite属性を 指定したCookie

Slide 21

Slide 21 text

CookieのSameSite属性 - 【参考】 Site: 公開接尾辞リスト + 直前のドメイン名 - 指定できる値 - Strict: 同一siteの場合のみ送信 - Lax: 異なるsite間の場合、GETの場合だけ送信 - None: どんな場合でも送信

Slide 22

Slide 22 text

つまりこう

Slide 23

Slide 23 text

ブラウザごとに挙動に差異が… - デフォルト(=指定しない場合)の挙動が異なるので、 明示的にきちんと指定しよう - Chrome: Laxと同様だが、Cookieセット後2分間は POSTの場合でもCookieが送られる(Lax+POST) - Safari: None。「サイト越えトラッキングを防ぐ」 設定によりそもそも送られないことも

Slide 24

Slide 24 text

SameSite属性利用のメリット - セッション用CookieにSameSite=Laxを指定する だけで防御を行うことができる(Strictでも可) - 異なるsiteからは送信されなくなるから お手軽でよさそう、なんだけど

Slide 25

Slide 25 text

SameSite属性利用のデメリット - 古いブラウザはSameSite属性に対応していない - GETの場合はCookieが送られてしまう(Laxの場合) - そもそもGETで状態変更できるリクエストは… - Cookieを利用しないアプリケーションでは使えない - 認証不要な場合とか

Slide 26

Slide 26 text

さらに中間者攻撃のリスクも - “http://example.com" と “https://example.com" は同一siteなのか問題 - ブラウザによって考え方が違う… - HTTPな経路でリクエストが改竄されてしまった場合、 攻撃を受けてしまう可能性がある

Slide 27

Slide 27 text

SameSite属性利用まとめ - Lax、Strictのいずれかを明示的に指定 - 中間者攻撃への対策としてはHSTSを有効化 (includeSubdomainsの指定を忘れずに) - 防御として、緩和はできるが穴があることがわかった - さて… 🤔

Slide 28

Slide 28 text

防御方法 3⃣ Originヘッダーを利用

Slide 29

Slide 29 text

Originヘッダーとは - ブラウザがリクエスト時にOriginヘッダーを付与する - https://developer.mozilla.org/ja/docs/ Web/HTTP/Headers/Origin - 同一Origin間のリクエストでは、 GET・HEADの場合は付与されないので注意

Slide 30

Slide 30 text

Originヘッダーを利用した防御 - リクエストのOriginヘッダーの値と サーバー側のホスト情報を照合 - 一致すれば正規なリクエスト、 一致しなければ不正なリクエストとして拒否 - そもそも送られてこなかったら拒否するようにする

Slide 31

Slide 31 text

つまりこう

Slide 32

Slide 32 text

Originヘッダー利用のメリット - 簡単、シンプルな手順で防御が可能 - 古いブラウザにも対応できる - Originヘッダーなしの場合、不正とみなす 最近採用されることが増えている

Slide 33

Slide 33 text

SvelteKitの例 - https://kit.svelte.dev/docs/con fi guration#csrf - https://github.com/sveltejs/kit/issues/72 - 最初はトークン方式(いろいろ)が提案されるが、 Originヘッダーの利用で十分では?と結論

Slide 34

Slide 34 text

Next.jsの例 - How to Think About Security in Next.js | Next.js (Server Actionsに関する記事) - Same-Site Cookieがブラウザで デフォルトで付くから防げるとか 🤔 (指定しようね) - HostとOriginのチェックも追加でやるよ、とのこと

Slide 35

Slide 35 text

Honoの例 - https://hono.dev/middleware/builtin/csrf - https://github.com/honojs/hono/pull/1823 - SvelteKitでの議論を参考に実装した、とのこと - v4も出たし注目のフレームワーク

Slide 36

Slide 36 text

防御方法 4⃣ Sec-Fetch-* ヘッダーを利用

Slide 37

Slide 37 text

Sec-Fetch-* ヘッダーとは - Sec-Fetch-Dest: fetchするリソースを使う形態 (documentとかimageとかfontとか) - Sec-Fetch-Mode: リクエストの形態 (navigateとかcorsとか) - Sec-Fetch-Site: リクエスト元Originとの関係 (same-originとかcross-siteとか)

Slide 38

Slide 38 text

Sec-Fetch-* ヘッダーを利用 - Sec-Fetch-Siteがsame-originであること - Sec-Fetch-Modeがnavigateであること - Sec-Fetch-Destがdocumentであること - 以上をそれぞれ検証すればよさそう

Slide 39

Slide 39 text

Sec-Fetch-* ヘッダー利用の特徴 - Originヘッダーの利用と同様にシンプルに防御可能 - ただし、ブラウザのサポートが割と最近 - https://caniuse.com/?search=Sec-Fetch- Site - 使えるけど、Originヘッダー利用で必要十分ではある

Slide 40

Slide 40 text

結局どうすれば いいの?

Slide 41

Slide 41 text

オススメパターン - 2⃣ セッション用CookieにはSameSite属性を指定 - __HOST- pre fi xを付けられるとなおよい - 3⃣ サーバー側ではOriginヘッダーをチェック - 4⃣ 追加として、Sec-Fetch-* ヘッダーもチェック - 送られてきていたらチェックするぐらい

Slide 42

Slide 42 text

でも結局のところ - フレームワークで用意されている方法を使うのが一番 - Web開発ではほとんどの場合フレームワークを使う - 1⃣ トークン方式も全然よいものだよ!!

Slide 43

Slide 43 text

今回話したかったこと (おまけ)

Slide 44

Slide 44 text

エンジニアとしての心がけ - 使っているフレームワークのことをよく知ろう - 使い方も大事だけど、仕組みに興味を持ってほしい - その上で、それ以外のやり方がないか調べよう - 異なる言語・フレームワークを触るときにきっと役立つ

Slide 45

Slide 45 text

ありがとう ございました!