レガシーの亡霊「JSONP」を葬り去れ:CORSで実現する現代的なクロスオリジン通信の鉄則
現場でコードレビューをしていると、未だに「古いシステムとの連携だから」という言い訳でJSONPを使っているケースに出くわす。正直に言おう。JSONPを使い続けることは、自ら鍵を開けたまま外出するようなものだ。
今回は、XSSの温床であるJSONPをなぜ今すぐ捨て、CORS(Cross-Origin Resource Sharing)へ移行すべきなのか。その技術的必然性と、今日から使える実装の「正解」を叩き込む。
—
1. なぜJSONPは「設計上の欠陥」なのか
JSONP(JSON with Padding)の仕組みは単純だ。タグはドメインを跨いで読み込めるという「仕様の隙」を突いている。
// JSONPの危険な呼び出し例 // callbackというパラメータに悪意ある関数名を仕込まれると…
攻撃者がこのcallbackパラメータを操作すれば、あなたのサイトのコンテキストで任意のJavaScriptを実行できる。これが反射型XSSの完成だ。さらに厄介なのは、JSONPはCORS以前の時代には「唯一の回避策」であったため、セキュリティ境界が曖昧なまま運用されているケースが多いことだ。
攻撃シナリオ:PoCの恐怖
攻撃者は、ターゲットのユーザーを罠サイトへ誘導し、セッションCookieを盗み出すスクリプトをJSONPのコールバック経由で流し込む。現代のWebアプリケーションにおいて、これは単なる「警告」ではなく、アカウント乗っ取りという最悪の結末を意味する。
---
2. CORS:ブラウザによる「信頼のゲートキーパー」
CORSは、JSONPのようにスクリプトを「注入」するのではなく、サーバー側が「誰からのリクエストを許可するか」をHTTPヘッダーで制御する仕組みだ。ブラウザが仲裁し、許可されたオリジン以外からの読み取りをブロックする。
実装の鉄則:ワイルドカードは禁忌
「とりあえず動けばいい」と Access-Control-Allow-Origin: を設定するのは厳禁だ。認証情報(CookieやAuthorizationヘッダー)を伴う通信では機能しないし、セキュリティリスクも大きい。
【サーバー側の実装例:PHP】
適切なホワイトリスト管理が鍵となる。
---
3. インフラレイヤーでの守り:Nginx設定
アプリケーションコードで制御できない場合や、フロントエンドの疎通確認をより厳格にしたい場合は、Nginxレベルで制御するのも有効だ。
Nginxの設定例
location /api/ {
# オリジンの検証ロジックをマップする
set $cors_origin "";
if ($http_origin ~ "^https?://(app\.example\.com|partner\.example\.com)$") {
set $cors_origin $http_origin;
}
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
# プリフライト対策
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Max-Age' 3600;
return 204;
}
}
---
4. 最後に:セキュリティは「信頼の積み重ね」
JSONPからCORSへの移行は、単なる技術的な書き換えではない。「外部からの入力をそのまま実行する」という古い悪癖を捨て、「厳格なオリジン検証」という現代の標準に乗り換えるという決断だ。
現場のエンジニアへ:
「動いているからいい」は脆弱性の入り口だ。JSONPのコードを見つけたら、それは技術的負債ではなく「時限爆弾」だと認識してほしい。
1. JSONPエンドポイントを特定する
2. 通信元のオリジンを洗い出す
3. CORSヘッダーを適切に設定し、JSONPを無効化する
この手順を徹底するだけで、あなたのプロダクトは格段に硬くなる。セキュリティは魔法ではなく、こうした泥臭い確認と適切な設定の積み重ねでしかないのだから。さあ、今すぐコードベースのクリーンアップに取り掛かろう。
コメント