HTML escape 是刻意將參與 HTML 語法的五個字元——& 號 (&)、小於 (<)、大於 (>)、雙引號 (") 以及單引號 (')——替換為具名或數值字元參考,而瀏覽器會將這些參考解析回字面文字。這個替換是精確的:只有這五個語法字元會對應到參考,一般的字母與數字則保持可讀,且解碼時是以相反方向執行。轉義之所以重要,是因為這五個字元正是 HTML 用來開始標籤、結束標籤、分隔屬性值,以及宣告實體參考本身的符號。如果它們在錯誤的脈絡中以未轉義的形式出現,瀏覽器就會停止讀取你的資料,轉而開始讀取你的標記,這正是版面破損、頁面結構錯誤,以及一類常見的注入漏洞的成因。實務上所謂的 HTML escape,是指理解轉義是一種在文字進入 HTML 之前對字串進行的轉換,而不是對已完成文件套用的過濾器。

html escape explained
HTML Escape 解析:從字元到實體

HTML Escape 真正的含義

HTML escape 背後的機制是一張針對五個具語法意義字元的固定替換表。在基本模式下,編碼器會將 & 號替換為 &amp;、小於替換為 &lt;、大於替換為 &gt;、雙引號替換為 &quot;,而單引號則替換為十進位參考 &#39;。除此之外不會有任何改變:一般的 ASCII 字母、數字、空格、定位字元與換行都會原封不動地通過,因此一段普通文字輸出的結果幾乎與輸入完全相同。有兩個實作細節會決定這張表是否能正確運作。首先,& 號必須在其他任何替換執行之前先被替換,因為表中其他所有參考都是以 & 號開頭的。如果先將小於轉義為 &lt;,那麼接下來處理 & 號的階段就會看到一個剛產生的 & 而再次將其編碼,產生重複的序列 &amp;lt;。其次,編碼器是逐一處理 Unicode 碼點,而非 UTF-16 碼元。這個差異在輔助字元(例如 😀(U+1F600))上會變得明顯:以碼點逐一處理會產生一個參考 &#x1F600;,而天真的 UTF-16 碼元逐一處理則會輸出兩個無效的代理碼參考。現代的 UTF-8 HTML 文件可以直接容納這類字元,因此 MDN 建議為了可讀性應避免不必要的數值參考。

編碼 vs 解碼:同一件事的兩面

HTML 實體編碼器 / 解碼器 提供了兩個互補的操作。編碼會將字面字元轉換為 HTML 字元參考,並僅保護這五個具語法意義的字元,讓其餘文字保持可讀。解碼則以相反方向進行,而且範圍比編碼表更廣:一個獨立的 textarea 元素會要求瀏覽器的 HTML 解析器解析 WHATWG HTML 現行標準目前所定義的每一個具名、十進位與十六進位參考。這個表格包含舊式別名以及對應到多個碼點的參考,因此像 &copy; 這樣的字串會解碼為 ©,即便編碼器根本不會產生那個參考。解碼的結果會以純文字形式回傳到一個唯讀欄位中。解碼後的值並不會插入到可見頁面中,也不會當作標記執行;它就只是等待被檢查並複製到合適脈絡中的文字。

HTML 語法中的五個保留字元

基本編碼表之所以簡短,是刻意為之。這五個字元是唯一會與解析器互動的輸入,因此也是唯一需要保護的輸入。

字面字元基本模式參考在 HTML 語法中的角色
&&amp;引入每個實體參考
<&lt;開啟起始標籤
>&gt;結束起始標籤
"&quot;界定雙引號屬性值
'&#39;界定單引號屬性值

非 ASCII 模式會執行同樣的五個替換,並另外將每個 ASCII 126 以上的碼點轉換為大寫十六進位數值參考。該模式存在是為了處理確實需要數值參考表示法的舊式或傳輸流程,而非用於日常可讀性。

如何在瀏覽器中編碼或解碼文字

  1. 選擇方向——編碼字元或解碼參考——並在編碼時,於基本模式與非 ASCII 模式之間擇一。
  2. 將來源文字貼入輸入欄位。該工具每次操作最多接受 500,000 個 JavaScript 字元。
  3. 執行轉換,輸出面板便會填入轉換後的字串。
  4. 檢查結果中是否有五個保留字元(在編碼模式下),或是否出現看起來像標記的文字(在解碼模式下)。
  5. 僅將結果複製到與此轉換所準備用途相符的脈絡中,例如文位元組點、屬性值或靜態說明文件頁面。

在貼上大量內容之前進行快速檢查時,可以先執行一個具代表性的短樣本,並確認 & 號與角括號看起來是否正確。這個頁面不會儲存歷史記錄、不會擷取遠端實體表,也不會傳送輸入內容,因此你所看到的,就是你瀏覽器所計算出來的結果。

為何轉義是與脈絡相關的,而不是與脈絡無關的

HTML escape 保護的是 HTML 文件中那五個語法字元。它不會保護任何其他語法。一段在某個段落內安全的字串,在 URL 參數、JavaScript 字串字面值、CSS 值、SQL 查詢或 HTTP 標頭中,未必同樣安全,因為這些語法各自使用不同的分隔符號。WHATWG HTML 現行標準 是具名參考表的權威來源,而 MDN 的字元參考詞彙表 則記錄了這些參考的解析方式。將這個工具視為淨化器是一種範疇錯誤:它會轉義字串中的字元,但無法阻止已完成文件在不安全的接收點中被渲染。解碼可能會顯示出看起來像標記的文字——<script> 會變成字面的 <script>——而這個解碼後的字串如果被貼入 innerHTML 接收點,依然會被執行。請將解碼後的輸出視為不可信任,並在最終輸出的邊界上套用與脈絡相符的轉義。

HTML Escape 何處開始不足以應付

一開始就值得點出三個界線。首先,XML 預先定義的實體集合比 HTML 小得多,因此像 &copy; 這樣在這裡能正確解碼的參考,在 XML 流程中可能無法通過驗證。其次,框架的自動轉義與可信賴的樣板引擎,已經能從具型別的值產生正確的轉義輸出;對其輸出再執行這個工具,最佳情況是冗餘,若樣板刻意嵌入 HTML,則最壞情況是會破壞結果。第三,內容安全政策(CSP)是另一道獨立的指令碼執行防線,無法以字串層級的轉義取代。此外,編碼器也不會把每個可列印字元都替換為具名實體,因為現代的 UTF-8 HTML 能直接承載 Unicode,多餘的參考只會讓原始碼更難閱讀。

這個工具適合用於以下情境:當你有原始文字必須通過 HTML 傳遞時;當你在閱讀混雜字面與已編碼片段的設定檔或樣板時;或當你需要先檢查某個字串,再決定它應該歸屬於何處。對於想要取得保留字元可列印摘要的讀者,HTML Escape 速查表:保留字元 指南彙整了同一張表,並列出每個轉義所必要的脈絡。

延伸閱讀:可在本機執行的免費 16 字元密碼產生器