XSSIの恐怖:なぜその「JSONデータ」は世界中に晒されているのか
現場のエンジニア諸君、お疲れ様。今日もコードと格闘していることだろう。
さて、今日は「XSSI(Cross-Site Script Inclusion)」という、少し渋いが非常に厄介な脆弱性について話そう。多くの開発者が「APIだからセーフ」「Cookieがあるから外部からはアクセスできない」と高を括っているが、実はその認識こそが、攻撃者にとっての格好の入り口なんだ。
XSSIは、端的に言えば「本来、自分しか見られないはずの機密データが、悪意あるサイトの <script> タグ経由で読み取られてしまう」という攻撃手法だ。JSONPのような古い手法だけでなく、現代のWebアプリケーションでも、静的なJSファイルや動的なJSONレスポンスを誤った方法で提供していると、このリスクから逃げられない。
攻撃のメカニズム:なぜ script タグが危険なのか
ブラウザの仕様上、<script> タグは、読み込むスクリプトが自分のドメインのものであるか、他人のドメインのものであるかを区別しない。
もし君たちが、認証済みのユーザーに対して以下のようなJSONを返すAPIを作ったとしよう。
{
"user_id": 12345,
"secret_token": "a1b2c3d4e5f6g7h8",
"email": "victim@example.com"
}
攻撃者は、被害者がログインしている状態で、自分の管理する攻撃用サイトに以下のタグを埋め込む。
<script src="https://your-app.com/api/user-info"></script>
ブラウザはログイン中のセッションCookieを添えてリクエストを送り、レスポンスを受け取る。ブラウザはこれを「スクリプト」として解釈しようとする。ここでJSONがJavaScriptの文法として妥当であれば、攻撃者はグローバル変数を汚染したり、あらかじめ定義しておいた関数をフックしたりすることで、この機密情報をいとも簡単に盗み出せるんだ。
守りの要:RefererチェックとSameSite属性
この攻撃を防ぐには、大きく分けて2つの鉄壁の守りが必要だ。
1. Referer または Origin ヘッダーの検証: 意図しないドメインからのリクエストを弾く。
2. SameSite 属性によるCookieの隔離: ブラウザレベルで外部サイトからのCookie送信をブロックする。
1. PHPでのReferer検証サンプル
まずは、サーバーサイドでリクエスト元を厳格にチェックする実装だ。
<?php
// 許可されたドメインリスト
$allowed_origins = ['https://trusted-app.com'];
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// RefererまたはOriginが許可リストに含まれているかチェック
$is_valid = false;
foreach ($allowed_origins as $host) {
if (strpos($referer, $host) === 0 || $origin === $host) {
$is_valid = true;
break;
}
}
if (!$is_valid) {
header('HTTP/1.1 403 Forbidden');
exit('Access Denied: Invalid Request Source');
}
// 正常なレスポンスの出力
header('Content-Type: application/json');
echo json_encode(['data' => 'secret_info']);
2. Cookieの SameSite 設定(Nginx/Webサーバー設定)
次に、Cookieの属性を Lax または Strict に設定することで、クロスサイトでのCookie送信を根本から防ぐ。これはセッションハイジャック対策としても必須だ。
# Nginx設定ファイルでのセッションCookie設定例
# Set-Cookieヘッダーに SameSite=Lax を付与する
fastcgi_param PHP_VALUE "session.cookie_samesite=Lax";
# より厳格にする場合は Strict を推奨
# fastcgi_param PHP_VALUE "session.cookie_samesite=Strict";
実務で「絶対に」やってはいけないこと
最後に、後輩諸君がよくやりがちなミスを挙げておく。
- JSONPの使用: 現代においてJSONPは「脆弱性を自ら作っている」ようなものだ。今すぐCORS(Cross-Origin Resource Sharing)に切り替えろ。
- 認証情報をURLに含める: どんな状況でも、機密情報がURLパラメータに漏れ出すような設計は避けること。
- X-Content-Type-Options: nosniff の欠落: レスポンスヘッダーに
X-Content-Type-Options: nosniffを必ず付与しろ。これを付けることで、ブラウザがJSONをスクリプトとして誤認して実行するのを防げる。
まとめ
XSSIの防御は、単なる「おまじない」ではなく、ブラウザの挙動を理解した上での「堅牢な設計」だ。
1. APIには必ず X-Content-Type-Options: nosniff を付ける。
2. Cookieには SameSite=Lax を必須にする。
3. 重要なデータへのアクセスには、必要に応じてCSRFトークンやRefererチェックを組み合わせる。
セキュリティは、魔法のような特効薬があるわけじゃない。こういった地味な設定の積み重ねが、君たちのサービスを、そしてユーザーの信頼を死守するんだ。明日からの開発で、一度自分のAPIのレスポンスヘッダーを見直してみてくれ。健闘を祈る。
コメント