管理画面を admin.example.com へ移すことは実際の改善です。管理用 Cookie を公開ページから遠ざけ、二つのアプリケーションに別々のキャッシュを与え、より厳しいネットワークポリシーを一つのホスト名に向けられます。ただしそれは CSRF の制御ではなく、公開サイトのコードをログイン済みの管理者の前で開いたままにして安全にするものでもありません。分離が変えるのはブラウザが境界と見なす範囲であり、サーバーが検査する内容ではありません。だから作業を終えたと判断する前に、この四つの確認を行ってください。

オリジンとサイトを別の言葉として読む

オリジンはスキーム、ホスト、ポートであり、https://www.example.com と https://admin.example.com は別のオリジンです。SameSite の意味でのサイトはスキームと登録可能ドメインであり、この二つのホスト名は通常同じサイトです。この違いが罠のすべてです。ブラウザはその要求をそもそもクロスサイトと見なさないため、SameSite 属性は兄弟サブドメインの間では役に立ちません。管理画面を admin-example.net のような本当に別の登録可能ドメインへ向ければ、要求は実際にクロスサイトになり、そこで初めて SameSite=Lax や Strict が信頼できる仕事を始めます。

理屈で考えるのではなく、ブラウザで試してください。

公開サイトを読み込み、開発者ツールを開き、管理ホスト宛ての要求にブラウザがどの Cookie を付けるかを見ます。Cookie に Domain 属性がなければホスト限定であり、自分のホスト名にとどまります。Domain=example.com を持っていればすべての兄弟ホストへ送られ、新しいサブドメインはその Cookie に関して何も得ていません。

応答を読めることと要求を送れることを分ける

同一オリジンポリシーが制限するのは、オリジンをまたいだ応答の読み取りです。要求の送信を止めるものではなく、ブラウザがすでに持つ資格情報をフォームが運ぶことも止めません。フォームの内容種別や単純な GET による単純要求は事前検査なしに届き、その後 CORS が呼び出し側スクリプトに応答を読ませるかを決めます。CSRF は完全に送信側にあります。

だからサーバーは状態を変える操作に明示的な検査を必要とします。セッションに結び付いた同期トークン、あるいはサーバー側で比較する二重送信 Cookie がその場合を覆います。Origin や Referer の比較は二つ目のゲートとして加える価値はありますが、唯一のゲートにはできません。すべての要求がそのヘッダーを運ぶわけではなく、すべてのプロキシが保持するわけでもないからです。OWASP の CSRF 防止ガイドが SameSite を複数の層の一つとして扱うのは、まさにこの理由です。

ネットワークのゲートが実際に何を証明するかを決める

管理ホストの前に置く VPN 出口の許可リストは良い制御であり、弱い身元の主張です。要求が VPN の配るアドレスから来たことは証明しますが、その出口を使う全員が共有し得るものであり、背後に誰あるいはどの端末がいるかは何も語りません。入口のフィルターとして扱い、認証として扱わないでください。

要求レベルの検査とは独立に保ってください。許可リストが攻撃者と状態を変える端点の間にある唯一のものであるなら、設定を誤った一つの経路、一つの split-tunnel クライアント、あるいは借りた一つのノート PC が制御を完全に外します。

想定した範囲の外からの拒否も記録してください。その急増は、誰かが今作った境界を探っているという最も有用な信号であり、沈黙はフィルターにまったく届いていないという信号です。

Cookie、サインイン、認可を明示的に保つ

Cookie の範囲が結果の大半を決めます。親ドメインの Cookie は管理ホストへ送られるため、公開サイト上のスクリプト注入は管理者のセッションで動けます。ホスト限定の Cookie はそれができません。ホスト限定の形を選び、Secure 属性を加え、対応するプラットフォームでは __Host- 接頭辞を使ってください。この接頭辞は Secure、Path=/、Domain 属性なしを要求します。Cookie の瓶ではなく応答ヘッダーを読んでください。Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax に Domain 属性はありません。ブラウザは Domain を持つ __Host- Cookie を捨てるので、兄弟ホストにまだ現れる Cookie は接頭辞が決して適用されなかった証拠です。

次に認可をサーバー側で、要求ごとに、すべての管理端点で保ってください。ログイン時だけでは足りません。許可されたネットワークから来た要求も、認証され、要求する操作について認可される必要があります。ホスト名は行為者ではありません。公開側と管理側のアプリケーションがサインインの流れやセッション保管を共有するなら、その関係を書き留めてください。公開サイトの不具合から管理操作へ至る最短の道だからです。

分離の後に境界を再確認する

正常系だけでなく否定的な試験を実行してください。トークンなしのクロスサイトフォームは拒否され、別セッションのトークンも拒否され、どの GET も状態を変えてはなりません。開発者ツールで Cookie の属性を確認し、一致しない要求で Origin 検査が働くことを確かめ、VPN の範囲外から管理ホストを試してフィルターが動くのを見てください。

これらのどれも、管理アプリケーション自体の内側にある XSS の欠陥を取り除きません。別のホスト名は実際の価値のあるブラウザ側の分離境界であり、安全でないコード実行の防止やサーバー側の要求保護の代わりにはなりません。分離後の一覧は見た目より短いものです。別のオリジン、ホスト限定 Cookie、変更ごとのトークン、身元として信頼しない入口フィルター、そして要求ごとに決める認可です。

関連記事