HTMLエンティティエンコーディングとは?
HTMLエンティティエンコーディングは、HTML内の特殊文字を対応するエンティティ参照に置き換える手法です。HTMLを記述する際、特定の文字には特別な意味があります:<はタグを開始し、>はタグを終了し、&はエンティティを開始し、"と'は属性値を区切ります。これらの文字をHTMLコードとして解釈されずにWebページにそのまま表示したい場合は、エンティティエンコーディングを使用する必要があります。
ブラウザはエンティティ参照をマークアップとして解釈せずに対応する文字としてレンダリングします。このメカニズムはWeb開発の基本であり、コンテンツ表示とセキュリティの両方で重要な役割を果たします。エンティティエンコーディングがないと、ユーザー生成コンテンツのすべての山括弧がHTMLとして扱われ、ページレイアウトが崩れたり、深刻なセキュリティ脆弱性が発生したりする可能性があります。
HTMLエンティティエンコーディングが重要な理由
HTMLエンティティエンコーディングには、特殊文字の正しいレンダリングとクロスサイトスクリプティング(XSS)攻撃の防止という2つの主な目的があります。<の代わりに<のようなエンティティを使用すると、ブラウザはHTMLタグの開始として解釈するのではなく、小なり記号を表示します。
これが重要になる最も一般的なシナリオは、ユーザー生成コンテンツです。アプリケーションがコメント、フォーラムの投稿、プロフィール説明を受け付ける場合は、HTMLでレンダリングする前に出力をエンコードする必要があります。エンコードしないと、ユーザーが <script>alert('xss')</script> を送信し、ブラウザがそれをJavaScriptとして実行し、攻撃者が訪問者のブラウザで実行されるコードを制御できるようになります。
一般的なHTMLエンティティリファレンス
| 文字 | エンティティ | 数値参照 | 説明 |
|---|---|---|---|
< |
< |
< |
小なり |
> |
> |
> |
大なり |
& |
& |
& |
アンパサンド |
" |
" |
" |
二重引用符 |
' |
' |
' |
アポストロフィ/一重引用符 |
|
|
  |
改行禁止スペース |
© |
© |
© |
著作権 |
® |
® |
® |
登録商標 |
™ |
™ |
™ |
商標 |
€ |
€ |
€ |
ユーロ通貨 |
エンコーディングの仕組み
HTMLパーサーが < に遭遇すると、& をエンティティ参照の開始として認識します。次にエンティティ名 lt を読み取り、セミコロンで終了します。パーサーはエンティティテーブルで lt を検索し、レンダリング出力で対応する文字 < に置き換えます。
数値文字参照も同様に機能しますが、10進数(<)または16進数(<)の値を使用します。パーサーは数値を対応するUnicodeコードポイントに変換します。数値参照は任意のUnicode文字を表現できますが、名前付きエンティティは頻繁に使用される文字のサブセットのみをカバーします。
ユーザー入力のエンコード
Web開発で最も重要なルールは、HTMLでレンダリングする前に、すべてのユーザー生成コンテンツをエンコードすることです。これはコンテキスチュアル出力エンコーディングと呼ばれ、データがアプリケーションを離れてHTMLコンテキストに入る時点で適用する必要があります。
PHPの例
$userInput = '<script>alert("xss")</script>';
$safe = htmlspecialchars($userInput, ENT_QUOTES | ENT_HTML5, 'UTF-8');
echo $safe;
// 出力: <script>alert("xss")</script>
JavaScriptの例
function encodeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
const userInput = '<script>alert("xss")</script>';
console.log(encodeHtml(userInput));
// 出力: <script>alert("xss")</script>
Pythonの例
import html
user_input = '<script>alert("xss")</script>'
safe = html.escape(user_input, quote=True)
print(safe)
# 出力: <script>alert("xss")</script>
Rubyの例
require 'erb'
user_input = '<script>alert("xss")</script>'
safe = ERB::Util.html_escape(user_input)
puts safe
# 出力: <script>alert("xss")</script>
エンコーディングのコンテキスト
HTMLエンコーディングは一律ではありません。HTMLドキュメント内の異なるコンテキストには、異なるエンコード戦略が必要です。
HTMLボディコンテキスト — <div>content</div> のようなタグ間のコンテンツ。<、>、&、"、' の5文字すべてをエンコードします。
HTML属性コンテキスト — <div class="value"> のような属性内の値。同じ5文字をエンコードしますが、引用符は属性値を区切るため特に注意が必要です。
URLコンテキスト — href や src 属性のURL。HTMLエンティティエンコーディングではなく、URLエンコーディング(スペースは %20)を使用します。
JavaScriptコンテキスト — <script> ブロック内に埋め込まれたデータ。HTMLエンティティエンコーディングではなく、JavaScript文字列エスケープ(< は \x3C)を使用します。
オンラインツール
Help2CodeのHTMLエンティティエンコーダー&デコーダーを使用すると、HTMLエンティティのエンコードとデコードが簡単に行えます。テキストを貼り付け、エンコードまたはデコードモードを選択し、ワンクリックで結果をコピーできます。本番コードを作成していない場合に、特殊文字を変換する最速の方法です。
セキュリティ:XSSの防止
クロスサイトスクリプティングは、今でも最も一般的なWebセキュリティ脆弱性の1つです。主要な防御策は適切な出力エンコーディングです。すべてのフレームワークには組み込みのエンコード関数があります:LaravelのBladeは {{ $var }} を使用して自動的に出力をエンコードし、Twigは {{ var|e('html') }} を使用し、ReactはJSX式を自動的にエスケープします。
最も一般的なXSS防止の誤りは、パイプラインの間違った時点でデータをエンコードすることです。データがレンダリングされる直前の出力レイヤーで常にエンコードしてください。データベースに保存するときにエンコードすると、二重エンコードや、JSON APIやメールテンプレートなどの非HTMLコンテキストで使用されるデータのエンコードのリスクがあります。
結論
HTMLエンティティエンコーディングは、すべてのWeb開発者にとって基本的なスキルです。特殊文字が正しく表示され、ユーザーをXSS攻撃から保護します。重要なルールはシンプルです:HTMLでレンダリングする前に、すべてのユーザー生成コンテンツをエンコードしてください。クイック変換にはHTMLエンティティエンコーダー&デコーダーツールを、本番コードではフレームワークの組み込みエンコーディングを使用してください。