はじめに
CORS・CSP・Same-Origin Policyについて、理解が深まったため整理する。
大前提の話
ブラウザは、HTMLの<form>
タグやJavaScriptのfetch()
などを使えば、別のサイトへ自由にリクエストを送ることができる。
<form action="https://victim.com/api/update" method="POST">
<input type="hidden" name="data" value="attack">
<input type="submit" value="送信">
</form>
このように、攻撃者のサイトからでも、他のサイトに対してPOSTリクエストを送ること自体は可能。
fetch() によるリクエストではレスポンスの制限がかかる(Same-Origin Policy)
JavaScriptのfetch()
を使って他のオリジンにリクエストを送ると、レスポンス自体は返ってくるが、ブラウザはそれをJavaScriptから読めないように制限する。
これは Same-Origin Policy(同一生成元ポリシー) によるもので、オリジン(プロトコル、ドメイン、ポート)が異なるとレスポンスの中身を読み取れないというセキュリティルール。
CORS(Cross-Origin Resource Sharing)で読み取りを許可できる
サーバ側がレスポンスヘッダーに以下のように記述すると、特定のオリジンからのレスポンス読み取りを許可できる。
Access-Control-Allow-Origin: https://frontend.example.com
この場合、https://frontend.example.com
上のJavaScriptからのfetch()
でのみ、レスポンスの中身を扱えるようになる。
CSP(Content-Security-Policy)はページが使えるリソースを制限する
CSP
は、そのWebページでどこから何を読み込めるかを制御するレスポンスヘッダー。
例えば、以下のようなヘッダーを返すと、
Content-Security-Policy: script-src 'self';
この場合、そのページは自分自身のドメイン(self)からのスクリプトだけ読み込みを許可し、他ドメインのスクリプトはブロックする。
同様に、style-src
, img-src
, connect-src
などでCSSや画像、AJAX通信先を制限できる。
CORSもCSPも「レスポンス後に効くセキュリティ」
CORSやCSPは、いずれもブラウザがレスポンスを受け取った後に適用されるセキュリティ機能。
つまり、「リクエストを送ること」自体を防ぐわけではない。
リクエスト内容の検証をするには、サーバーサイドでの検証が必要。
CSRFトークンによる検証
セッションベースでCSRFトークンを発行・検証する仕組みが有効
- フォームの作成時にトークンをセッションに保存
- フォーム内に hidden input で埋め込む
- サーバー側でトークンの一致を検証
こうすることで、「正しいフォームを通じて送信されたリクエスト」であることを保証できる。
まとめ
ブラウザには、CORSやCSP、Same-Origin Policyといったデフォルトのセキュリティ機構が備わっており、クロスオリジンの通信や不正なスクリプトの実行などに対して制限がかかる。
ただし、これらはあくまで「レスポンスをどう扱うか」に関する対策であり、「リクエストが正当なものかどうか」を検証する仕組みではない。
そのため、フォーム送信やAPI呼び出しにおけるリクエスト内容の検証するには、サーバーサイドでのセキュリティ対策が必須となる。