CookieのSameSite属性はCSRF対策のために提案されたもので、その属性をCookieに付与するだけでほとんどのサイトの場合はCSRF対策が可能になります。
しかし、SameSite属性の付与が今までのCSRF対策の代わりになり、今まで行ってきたCSRF対策をしなくてよくなるというわけではありません。
CSRF対策の為に提案された属性ですが、サイトの特性によってはCSRFを防ぐことができない場合があります。
今回は、その「防げないCSRF」とはどういったものであるのか、一例をあげます。
そして実際にSameSite属性付与が付与される脆弱なサンプルサイトを使って説明していきます。
目次
TL;DR
- 「防げるCSRF」とはセッションが存在しているサイト
- 「防げないCSRF」とはセッションを利用していないサイト
- SameSite属性は充分にCSRF対策の効果がある
サンプルアプリケーションを用いての検証
今回利用するサンプルアプリケーションのソース
GitHub - motikan2010/SameSiteCookieLaravelSample at blog_20190202
サンプルサイトの機能
下画像の画面遷移があるサンプルサイトを用意しました。 このAサイトの主な機能はBBSです。
ここで重要な点は「認証が不要な匿名BBS」と「認証が必要なログインBBS」があるということです。
そしてAサイトにリクエストを送信する罠フォームが配置されている、罠サイトがあります。
このサイト利用してCSRFの可否を確認していきますが、結果からいうと以下のようになります。
認証が不要な匿名BBS → CSRF可能 |
認証が必要なログインBBS → CSRF不可能 |
サンプルサイトはLaravelで実装されていますが、今回説明する内容は特定のフレームワークに依存するものではありません。
CSRF対策をCookieのSameSite属性のみで実施している場合に該当します。
CSRFの確認
この"Aサイト"と"罠サイト"を使ってCSRFが行われた場合の「匿名BBS」と「ログイン BBS」の挙動を比較してCSRFの可否を確認していきます。
CSRFトークンを用いている場合
これはよく使われるCSRF対策の方法です。
Aサイト内で発行されたCSRFトークンの検証が行われることによって、罠サイトからの不正なリクエストが正常に処理されないようにしています。
「匿名BBS」「ログインBBS」共にCSRFは不可能となりました。
SameSite属性を用いている場合
こちらはSameSite属性を用いたCSRF対策です。
Aサイト以外からのリクエストまたは遷移の際にはCookieが送信されなくなります。
Cookieを送信されなくなったことより、認証を必要とする「ログインBBS」に対するリクエストはエラーとなり、これがCSRF対策となっています。 → CSRF不可
対して、認証を必要としていない「匿名BBSに」対してはCookieの有無は関係なく処理がされるので、罠サイトからのリクエストも正常に処理されてしまいます。 → CSRF可能
このようにCookieのSameSite属性では、CSRFトークンを用いたCSRF対策の代わりにはならないことが確認できました。
認証を必要としない処理に対してのCSRFというのは、認証後の処理に比べ少々インパクトは劣りますが、そのCSRFを許容するということはないので、従来通りのCSRFトークンを用いでのCSRF対策が必須だと考えています。
まとめ
SameSite属性では全てのCSRFを防ぐことができませんが、認証後処理に対しては対策として充分効果を発揮すると思っています。
今はあまりよく見かけないSameSite属性ですが、今後のWebフレームワークのバージョンアップによってデフォルト設定になっていくと考えています。 (Spring boot 2.1ではセッションCookieにデフォルトで付与されるようになっていました)
これにより開発者がCSRF対策を実施せずに、とある画面はCSRF対策が全くされていないということにならないように気をつけていく必要がありそうですね。
- 「防げるCSRF」とはセッションが存在しているサイト → インパクト大
- 「防げないCSRF」とはセッションを利用していないサイト → インパクト小
- SameSite属性は充分にCSRF対策の効果がある → "インパクト大"を防ぐことは可能