なぜ危ないのか
XSSは攻撃者が悪意あるJavaScriptをページに挿入し、閲覧者のブラウザ上で実行させる攻撃です。社外レビュー用のHTMLでURLパラメーターをページ内に表示する機能がある場合、そのパラメーターがエスケープされずにDOMに挿入されていると、攻撃者がURLにスクリプトを仕込んで被害者に送り付けるフィッシング攻撃に使えます。
AIはユーザーの入力をリアルタイムで画面に反映するインタラクティブなUIを実装するとき、`innerHTML`や`document.write()`を使ったコードを生成することがあります。これらのメソッドはHTML文字列をそのままDOMに解釈するため、入力値が適切にサニタイズされていないとXSSの原因になります。特に検索フォーム、フィルター、プレビュー機能を含むHTMLは要注意です。
- 相手がログインなしで開ける状態か確認する
- PCとスマホで最低1回ずつ表示を確認する
- 内部情報・個人情報・不要な外部送信が残っていないか見る
- レビュー期限と修正時の差し替え方を決めておく
ソースで見る場所
最初に確認すべき危険なパターンは、`innerHTML`、`outerHTML`、`document.write()`、`eval()`の4つです。ターミナルで `grep -n 'innerHTML\|outerHTML\|document.write\|eval(' index.html` を実行して全件を洗い出します。これらがユーザー入力(URLパラメーター・フォーム値・localStorageの値)を直接受け取っている場合は、XSSが成立する可能性が高いです。
次に`addEventListener('message'`や`postMessage`を使っているコードを確認します。iframeとの通信に使われるこの機能は、送信元の検証なしに受信したデータをDOMに挿入するとXSSの経路になります。また`window.location.hash`や`URLSearchParams`からデータを取得してDOMに反映しているコードも要注意で、パラメーターの値が適切にエスケープされているか確認してください。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
安全に共有する設定
Content-Security-Policy(CSP)ヘッダーを設定するとXSSの被害を大幅に抑制できます。`Content-Security-Policy: default-src 'self'; script-src 'self'` という基本設定を配信サーバーに追加すると、インラインスクリプトと外部ドメインからのスクリプト読み込みが禁止されます。CSPを追加した後はページの表示が崩れていないかブラウザで確認してください。
社外共有用のURLには認証を追加し、URLを知っているだけではアクセスできない設定にします。XSSが存在したとしても、攻撃に使うには被害者が当該URLにアクセスしている必要があります。認証付き共有サービスを使えば、意図した相手以外が攻撃のターゲットになる経路を排除できます。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
再発防止ルール
AIへのプロンプトに「ユーザー入力をDOMに反映する場合はinnerHTMLを使わずtextContentまたはcreateTextNodeを使うこと。URLパラメーターを表示する場合はdecodeURIComponentとHTML特殊文字のエスケープを必ず実施すること」という制約を加えます。textContentはテキストとしてDOMに追加するためHTMLタグが解釈されず、XSSの原因になりません。
静的なHTMLスキャンツールとして`semgrep`の無料ルールセットを活用できます。`semgrep --config p/javascript-security *.html` を実行するとinnerHTML経由のDOM操作や危険なeval使用などをパターンマッチで検出します。CIに組み込めば継続的な品質管理が可能です。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
よくある質問
URLパラメーターをJavaScriptで読み取って表示するだけなら安全ですか?
読み取るだけでは安全ですが、取得した値をinnerHTMLやdocument.writeでDOMに挿入する瞬間に危険になります。表示にはtextContentを使い、HTML特殊文字(<>&"')をエスケープしてから渡してください。
静的なHTMLで入力フォームがない場合もXSSのリスクはありますか?
あります。URLのハッシュ(#以降)やクエリパラメーターをJavaScriptで読み取ってDOMに反映している場合は、フォームがなくてもXSSの入力経路になります。location.hashとURLSearchParamsを使っているコードを確認してください。
DOMPurifyというライブラリを使えばinnerHTMLを安全に使えますか?
DOMPurifyはXSSに特化したサニタイズライブラリで、innerHTMLに渡す前に悪意あるスクリプトを除去します。ただしDOMPurify自体を最新版に維持すること、および設定オプションを正しく指定することが前提条件です。