§

入力

モード
エンティティ形式
エンコード範囲
§

出力

IPA(情報処理推進機構)の「安全なウェブサイトの作り方」第7版では、XSS 対策として HTML 出力時のエンティティエスケープを筆頭に挙げています。JNSA のセキュアコーディング標準第 4 章「出力値のエンコード」でも、文脈に応じたエンコードルールを定めており、HTML ボディ・属性値・JavaScript コンテキストをそれぞれ区別するよう求めています。JPCERT/CC の Java セキュアコーディングガイドでも HTML エンティティエスケープが必須推奨事項とされています。このブラウザ完結型コーデックで、フレームワークが出力するエスケープ結果を素早く確認できます。

HTML エンティティエンコードの仕組み

HTML エンティティとは、ブラウザが解析して単一の文字に戻す文字参照です。<、>、&、"、' の 5 つの予約文字は、テキストを HTML としてレンダリングする際に必ずエンコードが必要です。それ以外の文字はオプションであり、ドキュメントのエンコーディングに依存します。

  1. モードと範囲を選択. エンコードモードでは入力を 1 文字ずつ処理します。デコードモードでは入力からエンティティパターンを検索します。範囲トグルで、HTML 安全文字 5 つのみをエンコードするか、非 ASCII コードポイントもすべて変換するかを決定します。
  2. エンティティ形式を選択. 名前付きエンティティ(&copy;)はソースで読みやすい形式です。10進参照(&#169;)と16進参照(&#xA9;)は名前なしで全 Unicode コードポイントを表現できます。古いメールクライアントや XML パーサーは数値形式を好みます。
  3. 入力を走査. エンコード時は各コードポイントを読み取り、約 200 の一般的な名前付きエンティティの内部テーブルを参照します。テーブルに存在しない文字は数値形式にフォールバックします。デコード時は &name;&#NNN;&#xHH; の 3 形式を 1 つの正規表現で一括スキャンします。
  4. 文字へのマッピング. 名前付きマッチは逆引きテーブルで解決します。数値マッチは 10 進または 16 進を指定した String.fromCodePoint で処理されます。未知の名前付きエンティティはそのまま保持されるため、部分的な入力でも情報損失なく変換できます。
  5. ライブモード. ライブモードをオンにすると、150 ms のデバウンスでキー入力のたびに変換が再実行されます。スニペットを微調整しながらテンプレートに貼り付ける前に即時フィードバックを得たい場合に便利です。

HTML エンティティをエンコードする理由

  • ユーザー入力によるレイアウト崩れを防ぐ. コメント欄にユーザーが < を入力すると、そのままHTMLに挿入するとページの残りの部分が書き換えられてしまいます。予約文字を事前にエンコードすることで、ブラウザはそれをタグの開始としてではなく文字として表示します。
  • 属性値の妥当性を保つ. クォートされた文字列を HTML 属性の中に埋め込む場合、引用符を &quot;(ダブルクォート属性の場合)や &#39;(シングルクォート属性の場合)に置き換える必要があります。そうしないとパーサーが属性を早期に閉じてしまい、残りの行が余分なマークアップになります。
  • 保存データ中の偶発的な HTML を無効化. ログ、バグレポート、チャットのエクスポートには実際の山括弧やアンパサンドが含まれることがあります。ドキュメントページに貼り付ける前にエンティティエンコードしておくことで、テキストとして表示され、レンダラーやリンク自動検出をトリガーしません。
  • コードスニペットを安全に共有. ブログ記事、メール、Slack メッセージに <script>alert(1)</script> のようなタグ例を投稿する際は、スニペットが実行されず表示されるよう括弧をエンコードする必要があります。この手法は RSS フィード本文や JSON-LD の `description` フィールドにも同様に適用されます。

一般的な用途

エンティティエンコードは、フレームワークが通常処理してくれる場面でも、そうでない場面での手動確認ツールとして、実行時に生のテキストが HTML に組み込まれる場所ならどこでも活躍します。

  • サーバーサイドテンプレート:Jinja2、ERB、Twig、Handlebars はデフォルトで自動エスケープを行いますが、raw ブロックや `safe` マーカーで無効になります — このコーデックでエスケープ結果を確認できます。
  • メール・ニュースレター作成:多くの ESP テンプレートエンジンはマージフィールドを自動エスケープしないため、ユーザー提供の名前に含まれるスマートクォートや著作権記号は事前エンコードが必要です。
  • ドキュメントとコードサンプル:HTML タグの例を Markdown ブログや静的サイトのスニペットに貼り付ける際は、レンダラーが可視テキストとして扱うよう括弧をエンコードする必要があります。

実際の例

<script>alert('hi')</script> を入力に貼り付け、モードをエンコード・スタイルを名前付き・範囲を最小に設定します。出力は &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt; となります。スタイルを数値16進に切り替えると同じ入力が &#x3C;script&#x3E;alert(&#x27;hi&#x27;)&#x3C;/script&#x3E; になります。モードをデコードに切り替えてエンコード済み文字列を貼り付けると、元のタグがそのまま戻ってきます。

FAQ

HTML エンティティとは何ですか?

HTML エンティティとは、ブラウザがページを解析する際に単一の文字に変換する文字参照です。名前付き(&amp;&)、10進数値(&#38;)、16進数値(&#x26;)の 3 形式があります。<>&"' の 5 つの予約文字は、テキストが HTML に挿入されるときは必ずエンコードが必要です。その他の約 2,225 の名前付きエンティティは記号・アクセント・ギリシャ文字などをカバーしますが、ドキュメントエンコーディングが UTF-8 であれば任意です。

名前付きエンティティと数値エンティティはどちらを使うべきですか?

ソースを読みやすくしたい場合は名前付きエンティティを使用してください(テンプレートレビュー担当者が &copy; を見ればすぐにわかります)。コンシューマーが古いまたは厳格な場合は数値(10進または16進)を使用してください。XML パーサー、レガシーメールクライアント、一部のフィードリーダーは HTML5 の名前付きエンティティのごく一部しか認識せず、数値形式はすべて認識します。セキュリティ重視の文脈では16進が好まれる傾向があり、仕様書で使用される Unicode コードポイント表記と一対一で対応するためです。

& のような16進エンティティはデコードできますか?

はい。デコーダーは &name;&#NNN;&#xHH; の 3 形式すべてを 1 パスで一致させる単一の正規表現を使用しています。数値マッチは 10 進または 16 進を指定した String.fromCodePoint で解決します。名前付きと数値が混在した入力(同一文字列内)も正しくデコードされ、未知の名前はリテラルテキストとして残されるため、部分的な入力でも情報損失なく変換されます。

信頼できない入力に対して安全に使用できますか?

コーデック自体はブラウザのみで動作し、入力をどこにも送信しません。出力を埋め込んでも安全かどうかはコンテキストによります。エンティティエンコードは HTML ボディと属性値コンテキストに対応しており、OWASP ルール #1 のケースをカバーします。JavaScript コンテキスト(インラインイベントハンドラー、`<script>` ブロック)、CSS コンテキスト、URL コンテキストにはそれぞれ独自のエンコードルールが必要であり、エンティティエンコード単体では不十分です。サーバーサイドの多層防御としては、DOMPurify やフレームワークの自動エスケープ機能と組み合わせて使用してください。

ブラウザ側でのエンティティエンコードは、ユーザー入力とレンダリングされた HTML の境界に位置します。ローカルで変換することで、元のテキストをサードパーティのツールに送信することなく、フレームワークが出力するエスケープ結果をその場で確認できます。