PHPセッションとSameSiteサポート – CSRF, XSS対策

(Last Updated On: 2018年8月13日)

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用のクッキーがあるかどうか?で判断できます。入力処理の段階でクロスサイトリクエストかどうか判断できます。

今の段階で同じようなことをする場合はこちらが参考になります。

PHPでCSRF対策を自動的に行う方法

 

投稿者: yohgaki