【実務・中級編】 クロスサイトスクリプトインクルージョン(XSSI)の防御 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

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のレスポンスヘッダーを見直してみてくれ。健闘を祈る。

コメント

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