「ユーザーが入力したテキストをそのまま表示したらタグとして解釈されてしまった」「& を含む商品名が文字化けする」——HTMLでテキストを扱うとき、特定の記号はエスケープしておかないと意図しない動作になります。
この記事では、HTMLエスケープが必要な特殊文字・変換ルール・XSS対策との関係・主要言語での実装例をまとめます。
下書きをすばやくエスケープしたい場合は、HTMLエスケープツールに貼り付けるとそのまま変換できます。
HTMLエスケープとは
HTMLエスケープとは、HTMLとして特別な意味を持つ文字(< > & " ' など)を、表示用のエンティティに置き換える処理のことです。
たとえば、<script> という文字をそのままHTMLに埋め込むと、ブラウザはタグとして解釈してしまいます。これを <script> に置き換えると、ブラウザは「タグではなくテキスト」として扱い、画面には <script> という文字列がそのまま表示されます。
この処理を行わないと、ユーザーの入力に含まれるタグやスクリプトが意図せず実行され、**XSS(クロスサイトスクリプティング)**などの脆弱性につながります。
エスケープが必要な主要な特殊文字
| 文字 | エンティティ | 説明 |
|---|---|---|
& | & | エンティティの開始記号。最初に変換する |
< | < | タグの開始記号 |
> | > | タグの終了記号 |
" | " | 属性値の区切り(ダブルクォート) |
' | ' または ' | 属性値の区切り(シングルクォート) |
' はXHTML/XMLでは標準ですが、古いブラウザのHTMLでは未対応な場合があるため、シングルクォートには ' を使うのが安全とされています。
変換の順序が重要
& を最後に変換すると、すでに作ったエンティティ(例:<)の & まで再変換されて壊れます。必ず & を最初に変換します。
1. & → &
2. < → <
3. > → >
4. " → "
5. ' → '
エスケープが必要なシーン
| シーン | エスケープ対象 | 補足 |
|---|---|---|
| HTML本文に表示するテキスト | < > & | <div>{userInput}</div> のような場面 |
| 属性値の中 | " ' < > & | <a title="..."> の ... 部分 |
| URLの中 | ? & などURL予約文字 | URLエンコード(別物)が必要 |
<script> の中 | JavaScriptとしてのエスケープ | 別ルール(JSON.stringifyなど)で対処 |
<style> の中 | CSSとしてのエスケープ | これも別ルール |
要するに「HTML本文・属性値・URL・JS・CSS」でそれぞれ求められるエスケープのルールが違う点に注意してください。HTMLエスケープをすればすべて安全、というわけではありません。
XSS脆弱性との関係
XSS(クロスサイトスクリプティング)は、攻撃者が用意した入力をWebページにそのまま表示してしまうことで発生する脆弱性です。
代表的なパターン:
ユーザー入力: <script>alert('XSS')</script>
そのまま表示 → スクリプトが実行されてしまう
これに対し、適切にエスケープすれば次のように無害化できます。
入力: <script>alert('XSS')</script>
出力: <script>alert('XSS')</script>
ブラウザは文字列として表示するだけで、スクリプトは実行されない
XSSは長年のウェブ開発で報告が多い脆弱性のひとつです。ユーザーが入力した値・外部APIから取得した値は、画面に出すときに必ずエスケープする、という方針が基本です。
主要言語・フレームワークでの実装例
JavaScript(手書き)
function escapeHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
React
JSX内で {value} のように埋め込む場合、Reactが自動でエスケープを行うため、追加処理は基本不要です。dangerouslySetInnerHTML を使う場合のみ自分で対処します。
Vue
Mustache {{ value }} でも自動エスケープされます。v-html を使う場合は要注意。
PHP
echo htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
ENT_QUOTES を指定するとシングル・ダブル両方のクォートをエスケープしてくれます。
Python(標準ライブラリ)
import html
html.escape(value)
Ruby on Rails
ERBの <%= value %> は自動でエスケープされます。あえて生のHTMLを出力したいときだけ <%== %> や raw を使います。
ブラウザツールでの変換
HTMLエスケープツールでは、ブラウザ内でテキストをエスケープ・アンエスケープできます。
- 設計書やGitHubコメントにHTMLサンプルをそのまま貼りたい
- ログから取り出したエスケープ済み文字列を元に戻したい
- メールテンプレートやCMS入力欄にHTMLを埋め込みたい
このような場面で、コードを書かずに変換できます。データはサーバーに送信されません。
よくある質問
Q. JSON.stringifyでXSS対策は十分ですか?
不十分なケースがあります。JSON.stringify は文字列をJSON形式に変換するだけで、HTMLとしての特殊文字(< > など)はそのまま残ります。HTMLに埋め込む際はHTMLエスケープも別途必要です。
Q. 属性値の中はダブルクォートを " にすればOK?
属性をダブルクォートで囲んでいる場合は最低限 " で対応できますが、シングルクォート区切りや属性値そのものを動的に組み立てるケースを考えると、< > & ' " をすべてエスケープしておくのが安全です。
Q. © のような既存のエンティティはエスケープすべき?
ユーザー入力としての © は、& を & にエスケープして &copy; として表示するのが原則です。サイト側の固定テキストとして「©記号を出したい」場合は、エスケープせずそのままエンティティを書きます。
Q. URLパラメータをHTMLに埋め込むときはどうする?
URLとして組み立てる段階でURLエンコードを行い、HTMLに埋め込む段階でHTMLエスケープを行う、と二段階で考えるのが基本です。
関連記事
- pxとremの違い — Web実装の単位の話
- 画像に透かしを入れる方法
関連ツール
- HTMLエスケープツール — HTML特殊文字を一括変換


