セキュリティ

XSSを防ぐAIプロンプトと公開前スキャン

XSSを防ぐには、AIへの指示(プロンプト)の時点で危険なパターンを生成させない工夫と、生成後にソースをスキャンする二段階の対策が有効だ。どちらか一方だけでは見落としが生じやすく、特にAIがデモ目的でevalやinnerHTMLを使い始めると、スキャンなしでは気づかないまま公開してしまうリスクがある。

なぜ危ないのか

AIはプロンプトに「インタラクティブなフォームを作って」と書くと、入力値を直接`innerHTML`に渡すコードを生成しがちだ。これはAIがXSSを意図しているわけではなく、手っ取り早く動くデモを返そうとした結果だが、受け取った側が内容を確認せず公開すると脆弱なHTMLが本番環境に載る。

生成されたHTMLをそのままzipにしてファイル便で送るケースも増えているが、受信者のPCでzipを展開してブラウザで開いた場合もXSSは発火する。ファイルプロトコルでのスクリプト実行はブラウザによって制限が異なり、ChromeとSafariで挙動が違うことも確認を複雑にしている。

フレームワークを使わない素のHTMLをAIで生成した場合は、ReactやVueが提供するエスケープ処理が自動では入らない。テンプレートリテラルで動的にHTMLを組み立てるパターンを含むコードが出力されることがあり、これを見落とすと後から修正コストが大きくなる。

  • 相手がログインなしで開ける状態か確認する
  • PCとスマホで最低1回ずつ表示を確認する
  • 内部情報・個人情報・不要な外部送信が残っていないか見る
  • レビュー期限と修正時の差し替え方を決めておく

ソースで見る場所

生成されたHTMLをスキャンするときはまず`innerHTML`の使用箇所を特定する。`grep -n 'innerHTML' output.html`を実行し、ヒットした行の右辺が固定文字列ではなく変数や関数の戻り値であれば要注意だ。変数の値がユーザー入力から来ている場合はXSSが成立する経路になる。

`eval`と`Function()`コンストラクタも同様にgrepで探す。AIがJSONのパースや動的な関数生成にこれらを使うことがあり、引数に外部から取得した文字列が渡されるとコードインジェクションになる。`new Function(`という文字列も忘れずに検索対象に含める。

スクリプトタグの`src`属性に`data:`URIや`javascript:`スキームが使われていないかも確認する。これらは一見無害に見えるが、Base64エンコードされたスクリプトを埋め込む際に悪用されるパターンがある。ブラウザの開発者ツールのNetworkタブでロードされるリソースを一覧表示してチェックするのが確実だ。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

安全に共有する設定

プロンプトレベルでXSSを予防するには、AIへの指示の末尾に「HTMLに埋め込むすべての動的な値はDOMPurifyまたはtextContentで出力し、innerHTMLへの直接代入は禁止」と明記するのが効果的だ。この制約を加えると、AIがgetElementById().textContent = userInputのような安全なパターンを選ぶ頻度が上がる。

生成後の自動スキャンをCIに組み込む場合は、Semgrepのルール`javascript.browser.security.insecure-document-method.insecure-document-method`が役立つ。HTMLファイルをリポジトリに置いているなら、GitHub Actionsのworkflowに`semgrep --config=p/xss`ステップを追加すれば、プッシュのたびにXSSパターンが検出される。

スキャンをパスしたHTMLを共有する際は、ギガサイト便のような会社ドメイン認証付きの共有サービスを使うと、意図しない相手のアクセスを防ぎながらレビューを完結できる。スキャン結果のログとURLの発行日時を社内ドキュメントに残しておくと、後から監査が必要になった際の証跡になる。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

再発防止ルール

プロジェクトのREADMEまたはAIプロンプトテンプレートに、XSS対策の制約文を定型句として追加しておく。「innerHTML禁止・eval禁止・外部スクリプトはSRI付きで読み込む」の三点セットをコピペできる形で用意しておけば、新しいメンバーが参加しても同じ品質で生成物を扱える。

週次または月次でリポジトリ内のHTMLをgrepスキャンするcronジョブを設定し、新たにコミットされたファイルにXSSパターンが混入していないかを継続監視する。Slackに通知するようにしておくと、検出した時点で素早く対処できる。

インシデントが発生した場合は、どのプロンプトがそのHTMLを生成したかを記録し、再発防止のためにプロンプトテンプレートを更新する。AIの出力はモデルのバージョンによって変わるため、定期的にサンプル生成して新バージョンが同じ安全なパターンを出力するか検証するサイクルを設けることが長期的な対策になる。

  • HTML内の外部script・form action・iframeを確認する
  • APIキーやトークンらしき文字列がないか検索する
  • 画像・CSS・JSのパスが公開後も解決できるか見る
  • noindexと認証を混同せず、必要なら両方設定する

よくある質問

DOMPurifyをHTML内に読み込むとき、そのCDN自体が乗っ取られるリスクはどう対処しますか?

SRI(Subresource Integrity)のintegrity属性をscriptタグに付与することで対処できる。DOMPurifyの公式GitHubリリースページにSRIハッシュが掲載されているので、それをコピーして使う。

Semgrepを使ったことがないのですが、ローカルで手軽に試すにはどうすればよいですか?

`pip install semgrep`またはHomebrewで入れた後、HTMLファイルのあるディレクトリで`semgrep --config=p/xss .`を実行する。初回はルールのダウンロードに数十秒かかるが、結果はターミナルに即表示される。

textContentを使えばXSSは完全に防げますか?

textContentはHTMLタグをエスケープしてテキストとして挿入するため、innerHTMLを使った直接代入より安全だ。ただしscript属性経由のXSSは別経路で発生するため、イベントハンドラ属性の排除も合わせて行う必要がある。

関連記事

セキュリティ

XSSを含むHTMLを共有するときのリスクと対策

XSSが含まれる可能性のあるHTMLを共有するリスクを把握し、適切な対策を講じたい担当者向け。被害シナリオ、コードレベルの修正方法、CSPによる軽減策、再発防止の仕組みづくりを段階的に解説します。

5分で読める
セキュリティ

クリックジャッキングを防ぐAIプロンプトと公開前スキャン

AIプロンプトの書き方を工夫してクリックジャッキングの原因となるコードをそもそも生成させたくない方向け。プロンプト制約の具体文例と、生成済みHTMLを素早くスキャンするコマンドを組み合わせた二段構えの防止策を解説します。

5分で読める
セキュリティ

http混在を防ぐAIプロンプトと公開前スキャン

AIを使ってHTMLを繰り返し生成する作業者向け。http混在を生成前に防ぐプロンプト設計と、生成後に素早くスキャンする方法を組み合わせ、毎回の手動チェック工数を減らしながらセキュリティ品質を維持する方法を紹介します。

5分で読める
セキュリティ

オープンリダイレクトを防ぐAIプロンプトと公開前スキャン

AI生成HTMLのオープンリダイレクトをプロンプト設計とスキャンツールの両面から防ぎたい開発者向け。プロンプトの制約文の書き方、grep・Semgrepを使った検出手順、修正パターンのサンプルを具体的に解説する。

6分で読める
セキュリティ

AI生成HTMLにXSSが残っていないか確認する方法

AIが生成したHTMLにXSSの脆弱性が残っていないか確認したい開発者・担当者向け。innerHTMLやevalなどの危険なパターンを検索するコマンド、ブラウザでの挙動確認、自動化の方法まで、公開前に完結できるXSSチェック手順をまとめます。

5分で読める
セキュリティ

社外レビュー前にXSSを検出するチェックリスト

社外レビューを依頼する前にAI生成HTMLのXSSリスクを洗い出したい開発者・デザイナー向け。inline scriptやevalの有無、外部送信先の特定方法など、公開前に一度だけ通るべき手順を解説する。

6分で読める
「セキュリティ」の記事をもっと見る →