【実務・中級編】CORS (Cross-Origin Resource Sharing) の不適切な設定とリスク – アプリケーションセキュリティ & 安全な開発防御ガイド

CORS設定の「思考停止」が招く悲劇:なぜワイルドカードは悪魔の誘惑なのか

現場でコードレビューをしていると、CORS(Cross-Origin Resource Sharing)の設定で Access-Control-Allow-Origin: を指定しているケースに遭遇することがある。エンジニアが「とりあえず動くように」と安易に書いたその一行が、実は企業の資産を外部に垂れ流す引き金になり得ることを、どれだけ自覚しているだろうか。

今回は、CORSの不適切な設定がなぜ危険なのか、そして現代のWeb開発で「絶対に守るべき実装」を実務レベルで解説する。

—

1. なぜワイルドカードは「全開のドア」なのか

CORSはブラウザの「同一オリジンポリシー」を緩和するための仕組みだ。本来、Webサイトは自分自身と同じドメインのリソースしか読み込めない。しかし、APIを別ドメインで運用する場合など、どうしてもクロスオリジン通信が必要になる。

ここで Access-Control-Allow-Origin: を指定するとどうなるか。「誰からのリクエストでも許可するし、レスポンスに含まれる機密データもすべて読み取らせる」という宣言になる。

もし、認証が必要なAPIや、個人情報を含むJSONを返すエンドポイントでこれをやれば、攻撃者は任意のサイトからあなたのAPIを叩き、ユーザーのブラウザを介してセッション情報を抜き取ることが可能になる。

攻撃のロジック(PoCの視点)

攻撃者が仕掛けるのは、悪意のあるページにユーザーを誘導し、背後で密かにAPIを叩かせる手法だ。
1. 罠サイトの作成: 攻撃者が自身のドメインで fetch('https://your-api.com/user-data') を実行するスクリプトを仕込む。
2. ブラウザの挙動: ブラウザは Origin: https://attacker.com を付与してリクエストを送る。
3. サーバーの応答: サーバーが Access-Control-Allow-Origin: を返すと、ブラウザは「よし、許可されているな」と判断し、レスポンスの内容をJavaScriptに渡してしまう。
4. 情報の流出: ユーザーがログイン中であれば、そのセッション情報を利用して個人情報が攻撃者のサーバーへ送信される。

—

2. セキュアな実装:ホワイトリスト運用を徹底せよ

「動けばいい」から「正しく制限する」への脱却が必要だ。基本原則は「信頼できるオリジンのみを許可し、動的に判定する」こと。

PHPでのセキュアな実装例

PHPでCORSを制御する場合、リクエストヘッダーの Origin を確認し、自社の許可リストに含まれている場合のみヘッダーを付与するのが鉄則だ。

Nginxでの設定(インフラ層での制御)

アプリケーションコードに修正を加えるのが難しい場合、Nginx側で制御するのも有効な防波堤になる。

許可するオリジンをmapで定義
map $http_origin $cors_origin {
default “”;
“https://app.example.com” “$http_origin”;
“https://dashboard.example.com” “$http_origin”;
}

server {
location /api/ {
# 動的にマッチしたオリジンをセット
add_header ‘Access-Control-Allow-Origin’ $cors_origin always;
add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS’ always;
add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;

if ($request_method = ‘OPTIONS’) {
return 204;
}
}
}

—

3. 現場で「やらかさない」ためのチェックリスト

実装が終わったら、以下の項目をセルフチェックしてほしい。これができていれば、重大なCORS起因のインシデントはほぼ確実に防げる。

  • [ ] ワイルドカードの排除: Access-Control-Allow-Origin: が本番環境の設定に残っていないか?
  • [ ] 正規表現の罠を回避: .\.example\.com のような雑な正規表現を使っていないか?(これだと example.com.attacker.jp も許可されてしまう)
  • [ ] Credentialsの取り扱い: Access-Control-Allow-Credentials: true を有効にする場合、Origin を必ず厳密に検証しているか?(“ と組み合わせることはブラウザで禁止されているが、論理的な漏れに注意)
  • [ ] プリフライトの最適化: OPTIONSメソッドに対するレスポンスが、不必要に詳細な情報を漏らしていないか確認しているか?

最後に:セキュリティは「設定」ではなく「設計」である

CORSの問題は、往々にして「開発時の利便性」を優先しすぎた結果として起きる。エンジニアにとって、セキュリティの設定は面倒な作業かもしれない。だが、一度のデータ流出が企業の信頼を地に落とし、君自身のエンジニアとしてのキャリアに影を落とすことを忘れないでほしい。

「面倒だから “ でいいや」と思った瞬間が、攻撃者にとっての扉が開く瞬間だ。その一行を書く前に、一度立ち止まって「誰を信頼すべきか」を自問自答してほしい。それが、世界最高峰の現場で生き残るための、最初のステップだ。

コメント

タイトルとURLをコピーしました