HTMLでは<、>、&という文字が特別な意味を持ち、エスケープが必須です。とはいえ日本語のテキストで実際にエンティティが問題になる場面は、ひらがな・カタカナ・漢字そのものよりも、古い文字コード時代の名残であることが多いです。
日本語にHTMLエンティティがほとんど不要な理由
ひらがな・カタカナ・漢字にはアルファベットのような「名前付きエンティティ」は存在しません。しかし現在のWebはほぼ全てUTF-8が前提のため、日本語の文字はそのままHTMLに書いても問題なく表示され、エンティティに変換する実用上の理由はほとんどありません。エンティティが必要になるのは、あくまで<や&のような構文上の予約文字だけです。
Shift_JIS・EUC-JP時代の文字化けとエンティティ
UTF-8が主流になる前、日本のWebサイトの多くはShift_JISやEUC-JPで文字コードを宣言していました。異なる文字コード間でデータをやり取りすると「文字化け」が起きやすく、当時はあのような数値文字参照が、文字コードに依存しない安全な受け渡し方法として重宝されていました。今でも古いRSSフィードやメールテンプレートにこの名残が残っていることがあります。
全角記号とHTMLの特殊文字の違い
日本語の文章でよく使う「」(かぎ括弧)や、全角の?!は、HTMLの構文で意味を持つ<や&とは無関係の、独立したUnicode文字です。そのためエスケープの対象にはならず、そのまま出力して問題ありません。日本語特有の記号とHTML予約文字を混同しないことが、エンコード処理を書く際のポイントです。
名前付きエンティティと数値エンティティ
HTMLエンティティは2通りの書き方があります。名前付きコード(<、&、")と数値コード(<、&、16進数なら<)です。ブラウザはどちらも同じように表示します。
エスケープすべき最低限の文字
<→<— タグが始まらないようにするため。>→>— タグの後のテキストを正しく閉じるため。&→&— &が別のエンティティの開始と解釈されないようにするため。"と'→"、'— 引用符で囲まれた属性値の中では必須。
XSSとの関係
多くのXSS脆弱性は、まさにユーザーが入力したテキストがエスケープされずにHTMLへ挿入されることで発生します。「<script>...</script>」をエンティティに変換せずに出力すると、ブラウザはそれをコードとして実行してしまいます。エスケープは基本的な——ただし唯一ではない——防御策です。
文脈が重要: テキストと属性の違い
<、>、&のエスケープはタグの間のテキストには十分ですが、引用符で囲まれた属性の中では、使用している引用符そのものも追加でエスケープする必要があります。属性が二重引用符で囲まれているのに値の中に未エスケープの二重引用符が含まれていると、マークアップは想定より早く断ち切られてしまいます。