HTML エンティティは、パーサーに誤って解釈されてしまう文字を HTML で表現するための仕組みです。タグの開始と見なされる山括弧、別のエンティティの開始と見なされるアンパサンド、エンコーディングの変換によって失われる可能性のある非 ASCII 文字などが対象です。エンティティを誤ると、レイアウトの崩れ・文字化け、最悪の場合は XSS 脆弱性を招きます。
HTML エンティティとは
HTML エンティティは & で始まり ; で終わる文字列で、1文字を表します。2種類の形式があります。
名前付きエンティティは説明的なキーワードを使います:
< → <
> → >
& → &
" → "
→ (改行なしスペース)
数値エンティティは Unicode コードポイントを10進数または16進数で使います:
< → < (10進数)
< → < (16進数)
© → ©
© → ©
どちらも同じ出力を生成します。名前付きエンティティの方が読みやすく、数値エンティティは名前付きに相当するものがない文字を含む任意の Unicode 文字に対応します。
HTML エンティティが重要な理由
HTML 構造の破壊を防ぐ
< と > は HTML で特別な意味を持ちます。ソースコードの表示など、リテラルの山括弧を表示する必要がある場合はエスケープが必要です:
<!-- NG: ブラウザが不完全なタグとして解析する -->
Using <strong> instead of <b> is preferred.
<!-- OK -->
<p>Using <strong> instead of <b> is preferred.</p>
XSS 脆弱性を防ぐ
ユーザーが入力したコンテンツを HTML に挿入する前にエスケープしないことは、最も一般的な Web セキュリティのバグの一つです。ユーザーが <script>alert(1)</script> と入力し、コードがそれをそのまま出力すれば、そのスクリプトはすべての訪問者のブラウザで実行されます。
<!-- 危険: ユーザー入力をそのまま出力 -->
<p>Hello, <%= username %></p>
<!-- 安全: HTML エンコード済み -->
<p>Hello, <%= htmlEncode(username) %></p>
HTML に挿入するユーザー入力には必ず以下の5文字をエンコードしてください:
| 文字 | エンティティ |
|---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
ドキュメントの文字セット外の文字を表示する
UTF-8 が普及する前は、ISO-8859-1(Latin-1)で配信されたドキュメントでは ©・€・— などを直接表現できず、エンティティが回避策でした。今日では UTF-8 での配信が標準ですが、簡単に入力できない文字やテキストプロセッサーに除去される可能性がある文字にはエンティティが便利です。
HTML エンティティ早見表
予約文字
| 文字 | 名前 | エンティティ | 数値参照 |
|---|---|---|---|
< | 小なり記号 | < | < |
> | 大なり記号 | > | > |
& | アンパサンド | & | & |
" | ダブルクォート | " | " |
' | シングルクォート | ' | ' |
タイポグラフィ
| 文字 | 名前 | エンティティ | 用途 |
|---|---|---|---|
| 改行なしスペース | | 単語間の改行を防止 |
— | 全角ダッシュ | — | 文の区切り、範囲 |
– | 半角ダッシュ | – | 数値の範囲(2010–2024) |
… | 省略記号 | … | テキストの省略 |
" | 左ダブルクォート | “ | 引用 |
" | 右ダブルクォート | ” | 引用 |
' | アポストロフィ | ’ | 短縮形 |
シンボル
| 文字 | 名前 | エンティティ |
|---|---|---|
© | 著作権 | © |
® | 登録商標 | ® |
™ | 商標 | ™ |
€ | ユーロ | € |
£ | ポンド | £ |
¥ | 円/元 | ¥ |
° | 度 | ° |
± | プラスマイナス | ± |
× | 乗算 | × |
÷ | 除算 | ÷ |
→ | 右矢印 | → |
数学記号
| 文字 | 名前 | エンティティ |
|---|---|---|
≤ | 以下 | ≤ |
≥ | 以上 | ≥ |
≠ | 不等号 | ≠ |
∞ | 無限大 | ∞ |
∑ | 総和 | ∑ |
√ | 平方根 | √ |
コードでのエンコード・デコード
JavaScript
ブラウザの DOM が HTML エンティティのエンコードを処理します:
// エンコード(HTML エスケープ)
function htmlEncode(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
htmlEncode('<script>alert(1)</script>');
// "<script>alert(1)</script>"
// デコード(HTML アンエスケープ)
function htmlDecode(str) {
const div = document.createElement('div');
div.innerHTML = str;
return div.textContent;
}
htmlDecode('<b>bold</b>');
// "<b>bold</b>"
Node.js(DOM なし)の場合はライブラリを使います:
npm install he
import he from 'he';
he.encode('<script>alert(1)</script>');
// "<script>alert(1)</script>"
he.decode('<b>bold</b>');
// "<b>bold</b>"
Python
Python 標準ライブラリで一般的なケースを処理できます:
import html
# エンコード
html.escape('<script>alert(1)</script>')
# '<script>alert(1)</script>'
# シングルクォートを含めてエンコード
html.escape("it's a test", quote=True)
# 'it's a test'
# デコード
html.unescape('<b>Hello & World</b>')
# '<b>Hello & World</b>'
PHP
// HTML コンテキスト用エンコード
htmlspecialchars('<script>alert(1)</script>', ENT_QUOTES, 'UTF-8');
// <script>alert(1)</script>
// 適用可能なすべての文字をエンコード
htmlentities('© 2024', ENT_QUOTES, 'UTF-8');
// © 2024
// デコード
html_entity_decode('<b>bold</b>', ENT_QUOTES, 'UTF-8');
// <b>bold</b>
エンコードすべき場合・しなくていい場合
必ずエンコードする:信頼できない入力(ユーザー名・検索クエリ・フォーム値・API データ)を HTML に挿入する場合。
二重エンコードしない。 コンテンツがすでにエンコードされている場合(データベースに < として保存されている場合)、再度エンコードすると &lt; になり、< ではなくリテラルの < として表示されます。
非 ASCII テキストには UTF-8 をエンティティの代わりに使う。 UTF-8 として配信・保存すれば ©・€・→ をエンティティなしで HTML に直接使えます。レガシーまたは制約のある環境でのみエンティティが必要です。
は控えめに使う。 は HTML メールのスペースハックや改行防止によく使われますが、現代の HTML/CSS では white-space: nowrap や word-break プロパティの方が保守しやすいです。
クイック検索ツール
文字のエンティティを調べたり、ソースコードで見かけたエンティティをデコードしたい場合、最速の方法は専用のエンコーダー/デコーダーです。ZeroTool HTML エンティティツールを試す →
HTML エンティティを含むテキストを貼り付けてデコード、または特殊文字を入力・貼り付けてエンティティ表現を取得できます。用途:
- CMS エクスポートから文字化けした HTML をデコード
- 見た目しかわからない記号の正しいエンティティを調べる
- テンプレートのエスケープが正しく機能しているか確認
まとめ
HTML エンティティは2つの重要な役割を果たします。予約文字を HTML 構造を壊さずに表示することと、ユーザー入力をエスケープして XSS を防ぐことです。現代の UTF-8 ドキュメントでは、エスケープに必要なのは基本的に <・>・&・"・' だけで、残りの文字セットは直接挿入できます。