CSRF対策は長らくCSRFトークン検証が主流で来ましたが、いまクッキーのSameSite属性で制御する方式に切り替わろうとしています。経緯については CSRF is (really) deadに詳しい解説があり参考になります。
SameSite=Lax
を指定することで、別ドメインへのPOSTリクエストにはブラウザがクッキーを送らない挙動となります。これにより、サイト運営者から見れば、他サイトから偽リクエストが送られてきたとしても、未ログイン状態となりログインを要する処理は自然に拒否できるという挙動になります。
COVID-19の影響でロールアウトが遅れていたものの、ブラウザのデフォルト設定が今まさにSameSite=Laxに変わりつつあります。
それと同時に、一部のサイトでは非互換が起きうるため、SameSite属性を従来と同じ設定にするという動きもあるのですが、ガードを下げる努力をすることは良くないと言えます。
むしろ逆に、SameSite=Laxを明示的に指定して、クライアント動作のバラつきを減らした方が制御しやすいでしょう。そのためには、サイト内のクロスドメインPOSTを撤廃することが必要です。
またこれに合わせて、重要なリクエストについてはPOSTに切り替える検討も有効でしょう。CSRF攻撃から保護されます。なお、これは一時注目を集めたRESTアーキテクチャとは矛盾が生じます。
RESTでは語彙が不足するケースが多いことから、近年ではgRPCなどのWebRPCが人気を得ており、WebAPI方式は様々なレイヤで見直すべき時期を迎えています。
Cookieのライフタイム
Laxと直接関係ないのですが、Cookieの設定変更をする機会はあまりないことから、ライフタイムについても見直しておいた方が良いでしょう。
Cookieの有効期限は設定しだいであり、期限のないCookieは設定変更時の挙動の見通しが悪くなるため、何らかの期間設定をした方が制御しやすいと言えます。
期限のないCookieはブラウザセッションでリフレッシュされる仕様で、以前はブラウザを閉じると消えていました。ところが、最近はタブの保存機能などを利用していると期限切れにならないようです。これにより、クッキーのエントリが重複した場合、セッションが全体的に動作しなくなります。
Ruby on Railsのケース
Railsのクッキー処理は、下層のRackが引き受けています。Lax設定は2015年末リリースの
Version2.0.0.alphaで導入されています。
Rackは継続的にセキュリティ対策を実装してきているため、ある程度新版にアップデートしたうえで設定すべきでしょう。ただし、バージョン間でセッションキーのロジックに非互換があるため、古いRackを利用しているサービスでは注意が必要です。
また、ブラウザのサポート状況は CanIuseで確認できます。
具体的な設定は、Railsのconfig.session_sotre
にsame_site: :lax
というオプションを追加することで指定可能です。
再起動するとSameSite=Laxで動作します。とくに問題なければ、セッションストアをクリアするとブラウザ側の書き換えも早く進みます。ブラウザの動作確認は、たとえばChromeデベロッパーツールのApplicationタブのCookies欄などを利用できるでしょう。
また、RailsはデフォルトでCSRFトークンを検証しますが、以下の設定でdisableにもできます。とくに動作に支障がなければ、CSRFトークンの検証はLaxと併用で継続する手もあります。
config.action_controller.allow_forgery_protection = false
なおこの設定で機能をオフにした場合、Controller中のprotect_from_forgery
メソッドなどはエラーになるため、機能ごとオフにする際はメソッドの除去も必要になります。
Chuma Takahiro