PHPのセッションID用クッキーと他のクッキー関数にSameSiteサポートが追加されます。
https://wiki.php.net/rfc/same-site-cookie
これによりクロスサイト・リクエスト・フォージェリ攻撃(CSRFやXSS)などを緩和できます。
仕様
setcookie, setrawcookie, session_set_cookie_paramsの第4引数/第2引数に配列としてpath, domain, secure, httponly, samesiteが設定できる。
今までの属性は個別の引数として設定できましたが、SameSiteは配列としてのみ設定できます。
同じサイトからのリクエストの場合のみクッキーを設定する:samesite = Strict
$cookie_opt = [ 'secure' => true, 'httponly' => true, 'samesite' => 'Strict', ];
他のサイトからのリクエストでもクッキーを設定する:samesite = Lax
$cookie_opt = [ 'secure' => true, 'httponly' => true, 'samesite' => 'Lax', ];
のようにします。
注意点
samesiteをStrictに設定した場合、クッキーが設定されません。つまりセッションモジュールから見ると新しいリクエストのように見えます。
普通にsession_start()を実行すると、新しいセッションIDクッキーが設定されます。このため
- ログイン中のセッションIDが上書きされる(ログアウトした状態になる)
- 不必要に大量のセッションが作られる可能性がある
といった問題が発生します。
サポートするブラウザも限られている点にも注意が必要です。
ログインセッション上書き防止
ログインセッションのセッションID上書きを防止するにはSameSiteを設定していない別のクッキーを用意します。
- SameSiteを除くセッションIDと同じ属性(Path, Domain, Secure, HttpOnly, Expire)を持つ”別の”クッキーに認証済みフラグを設定する。
- 認証済みフラグがある場合、session_start()は実行せず、予め決めておいた自分のサイトのページにリダイレクトする。
- このページでクロスサイトリクエストであることを説明し、実際にリクエストを実行するのか確認する。(必要な場合)
上記のような対策が必要になります。
まとめ
アプリケーションの改修なしでセッションIDに使うには問題がありますが、多層防御の1つといて利用するのは十分ありでしょう。
例えば、単純なCSRF対策ならsamesite=StrictでNoCSRFクッキーを設定し、$_COOKIE[‘NoCSRF’]が設定されているならクロスサイト攻撃でない、と判断できます。
今のところsamesiteをサポートしないブラウザがあり、上記のCSRF対策だけにすることはできません。しかし、将来的にはsamesiteクッキーの確認だけでクロスサイト攻撃の防止が可能になるでしょう。
すべてブラウザでsamesiteが使えると仮定しCSRF対策をする場合、セッションを開始する前にセッションID用のクッキーがあるかどうか?で判断できます。入力処理の段階でクロスサイトリクエストかどうか判断できます。
今の段階で同じようなことをする場合はこちらが参考になります。