なぜ危ないのか
XSSが成功すると攻撃者はページ上でJavaScriptを自由に実行でき、ログイン中のセッションCookieを盗んだり、フォームの入力内容を外部サーバーに送信したりできます。社外レビュー用HTMLがクライアントの社内システムにログインした状態のブラウザで開かれた場合、そのセッション情報が攻撃者に送られる最悪のシナリオも理論上は成立します。
Stored XSS(永続型XSS)はデータベースに悪意あるスクリプトを保存させる攻撃ですが、AIが生成するHTMLで特に問題になるのはReflected XSS(反射型XSS)です。URLパラメーターに`<script>alert(1)</script>`を含めてアクセスするだけで脆弱性の存在を確認できるほどシンプルな攻撃で、標的型フィッシングメールに悪意あるURLを埋め込んで送付するといった実際の攻撃に使われます。
- 相手がログインなしで開ける状態か確認する
- PCとスマホで最低1回ずつ表示を確認する
- 内部情報・個人情報・不要な外部送信が残っていないか見る
- レビュー期限と修正時の差し替え方を決めておく
ソースで見る場所
AIが生成する動的コンテンツ表示でよく見られるXSSパターンの例:`document.getElementById('output').innerHTML = location.hash.slice(1)` は、URLの#以降をそのままHTMLとして挿入します。このコードはURLが `page.html#<img src=x onerror=alert(1)>` のような形式で送られてきたとき、alertが実行されます。
JavaScript内のテンプレートリテラル(バッククォート)で作るHTML文字列も要注意です。`const html = \`<div>${userInput}</div>\`` というパターンでuserInputがサニタイズされていない場合、そのまま`innerHTML`に渡すとXSSになります。grepで`\$\{` を含む行を抽出し、その変数がどこから取得されているかを追跡してください。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
安全に共有する設定
XSSが含まれる疑いのあるHTMLを発見した場合、まず社外共有URLを即時無効化します。無効化と並行して、問題のあるコードを修正します。innerHTML経由で動的コンテンツを表示しているすべての箇所を特定し、textContentへの置き換えまたはDOMPurifyによるサニタイズを実施してから修正版を再公開します。
修正版の再公開前にContent-Security-Policy: script-src 'self' ヘッダーを設定すると、インラインスクリプトの実行を防げます。ただしAIが生成したHTMLはインラインスクリプトを多用するため、CSPを有効化するとページの機能が壊れる可能性があります。CSP適用後に主要機能が正常動作するかどうかをブラウザのコンソールでエラーを確認しながら検証してください。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
再発防止ルール
AIへのプロンプトに「ユーザー入力またはURLパラメーターをDOMに表示する場合は次の関数でサニタイズしてから使うこと:`function escapeHtml(str) { return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,'''); }` を必ずコードに含めること」と明記します。サニタイズ関数を明示することでAIが関数を生成し忘れるケースを防げます。
公開前のXSSチェックとして「URLに `?test=<script>alert(document.domain)</script>` を付けて開いてアラートが表示されないか確認する」という手順をチェックリストに加えます。XSSが存在するとアラートが表示されるため、目視で即座に判断できます。この確認は2分以内に完了でき、技術的な知識がなくても実施できます。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
よくある質問
完全に静的なHTMLでJavaScriptを一切使っていない場合もXSSはありえますか?
JavaScriptがゼロなら通常のXSSは成立しません。ただしHTMLの属性値にURLを入れる箇所(a hrefやimg srcなど)で`javascript:`スキームが使用可能な場合は別途確認が必要です。
XSSと同時にCSRFも対策すべきですか?
CSRFはサーバー側のエンドポイントへの対策なので、静的HTMLのみの場合は直接の関係はありません。フォームの送信先にサーバーAPIがある場合はCSRFトークンの実装も必要です。
AIにセキュアなコードを書かせるために最も効果的な指示は何ですか?
「OWASPのXSS防止チートシートに従うこと」と「ユーザー入力を扱う箇所はすべてサニタイズ処理のコメントを付けること」を組み合わせると、具体的な制約と可視性が同時に確保でき効果的です。