電子郵件地址編碼器會把一個公開的聯絡地址,轉成一個 HTML 錨點,其可見文字與 mailto 目標整個都寫成十進位數值 HTML 字元參照,因此頁面原始碼中不含任何字面上的 @ 或網域字元,訪客卻仍然能看到一個可點擊的地址。Email Address Obfuscator 會在瀏覽器本機完成這種編碼:顯示文字與 href 中的每一個 Unicode 碼位,都會變成像小寫 a 的 a 這樣的形式,mailto: 前綴也會被保留成一串十進位字元實體,最終的錨點在其原始碼的任何地方,都不會出現字面上的地址字元。因為這個工具絕不會把地址傳送到遠端伺服器,編碼後的結果可以隨時重現、方便程式碼審查稽核,也適合對一般公開網站地址公開發布。輸出結果仍然是一個可正常運作的 mailto 連結,點擊、複製或儲存時,都會開啟訪客所設定的電子郵件客戶端,這讓頁面對真正的讀者仍然有用,同時讓原始碼更難被非常基本的純文字爬蟲比對出來。這種編碼是純粹的靜態 HTML,而不是由 JavaScript 注入的標記,因此停用指令碼的訪客仍然能看到一個可運作的連結,內容安全政策標頭也不會因為內嵌事件處理器而受到壓力。

email address encoder
email address encoder

這個編碼器會在你的 HTML 中寫入什麼

編碼器做的不只是把 @ 符號換成一張圖片,或把可見的字母打散。它會把整個錨點——包括開始與結束標籤之間人類可讀的文字,以及訪客點擊時瀏覽器會解析的 href 值——全部重寫成一連串定義於 WHATWG HTML character references 規範中的十進位數值字元參照。結果仍然是普通的靜態 HTML。瀏覽器在渲染時會剖析這些實體並顯示原始字元;訪客看到的,正好就是用一個普通錨點會看到的地址。差異只有在檢視原始碼時才會顯現:沒有 [email protected] 這樣的字串可以讓一個粗淺的爬蟲直接抓取。

輸出的形狀在不同輸入之間維持一致。一個 <a> 元素會包住編碼後的可見文字,一個 href 屬性會包住編碼後的 mailto: 前綴加上編碼後的地址。本地部分會保留原本的大小寫與支援的標點符號,網域會先轉成小寫再編碼,國際化網域則會序列化成其與 ASCII 相容的形式,讓同樣的輸出在不同瀏覽器間都能重現。因為每一個碼位都會被編碼,就連句點、連字號、加號、斜線,以及 @ 字元,也都會經過實體這一層,而不是以字面本身出現。這個連結仍然可以點擊、仍然會解析成一個 mailto 網址,也仍然會用正確的地址觸發訪客的電子郵件處理程式。

產生並貼上只含實體的錨點

在一個公開聯絡頁面上使用這個編碼器的完整流程很短,但每一步都很重要。用 Email Address Obfuscator 完成編碼這一步,接著把結果搬進一個受控的 HTML 範本,而不是一個可能在儲存時重寫實體的內容編輯器。

  1. 輸入公開的聯絡地址,並在本機產生錨點。 把地址輸入到欄位中、送出,讓工具在你的瀏覽器中產生完整的編碼後錨點。這個地址不會離開頁面;驗證器會檢查格式,編碼器會一次就輸出這些實體。
  2. 把完整的錨點複製到一個 HTML 原始碼範本中,而不是富文本編輯器。 把這段程式碼片段貼到你 CMS 的 HTML 檢視畫面、一個靜態範本檔案,或任何會儲存原始標記的環境中。避免貼到可能會把 &#97; 中的 & 重新編碼、或直接把實體整個剝掉的所見即所得編輯器。
  3. 開啟正式發布的頁面、檢視原始碼、點擊一次連結,並確認敏感地址已備有聯絡表單。 發布之後,在正式上線的頁面上檢視原始碼:字面上的地址字元應該完全不存在,實體也應該仍然顯示為 &#97;,而不是解碼後的 a。點擊連結以確認郵件客戶端收到的是你原本想要的地址。如果這個地址實際上正在遭受容易被濫用的流量,就加上一個具備驗證與速率限制的伺服器端聯絡表單,讓這個編碼錨點只是其中一層,而不是唯一的一層。

驗證器如何限定被接受的地址格式

這個編碼器並不打算符合特殊郵件系統所允許的每一種信箱語法。它接受的是一個實用、未加引號的本地部分,後面接一個由多個標籤組成的公開網域,本地部分中不含空白或控制字元,也不允許開頭、結尾,或連續的句點。國際化網域會被接受並轉換成其與 ASCII 相容的形式;IPv4 字面值、單一標籤主機、加引號的本地部分、註解,以及網域字面值都會被拒絕,因為這個編碼器針對的是一般的公開網站地址,而不是郵件伺服器在私有網路上可能接受的每一種特殊形式。本地部分會保留原本的大小寫與支援的標點符號。這個驗證器刻意設計得比完整的電子郵件標準更狹窄:一個寬鬆的剖析器要嘛會放行這個工具無法安全編碼的輸入,要嘛會接受看起來正確、卻永遠到不了真正收件匣的地址。

輸入格式是否接受原因
[email protected]單一未加引號的本地部分、多標籤網域、不含空白。
[email protected]支援本地部分中的加號定址與句點。
[email protected]國際化網域會被正規化成其與 ASCII 相容的形式。
[email protected]對一般公開網站地址而言,IPv4 字面值會被拒絕。
user@localhost單一標籤的主機會被拒絕。
[email protected]本地部分開頭、結尾,或連續的句點會被拒絕。
"quoted"@domain.com加引號的本地部分不在這個實用、未加引號的子集範圍內。
missing-at-symbol.com必須恰好有一個 @ 符號。

這個驗證器並不會測試這個信箱是否實際存在、能否收信,或是否屬於某個特定的人。一個格式有效的地址,仍然可能被退信,或轉發到不存在的地方,因此這個編碼器從不暗示任何可送達性保證。

為什麼數值實體混淆不是垃圾郵件防護

這個編碼器所使用的技術是混淆,不是安全防護。數值字元參照是 HTML 的一項渲染特性;任何能剖析 HTML 的程式——基本上包含幾乎所有現代爬蟲——都能解碼它們、走訪 DOM、追蹤 mailto 目標,或讀取訪客原本會點擊的連結。一個只在任何 HTML 被剖析之前、單純搜尋一般地址樣式的非常基本的爬蟲,可能會漏掉這種編碼後的形式。除了這個最低門檻之外,這層防護就消失了。現代爬蟲會剖析 HTML、解碼實體、檢查渲染後的 DOM,甚至會把 mailto 連結解析成它們會送達的地址。無論如何編碼,一個公開渲染出來的地址,對訪客與有能力的機器人來說仍然是可被發現的。

Mailto 連結還有其他暴露面。在許多瀏覽器中點擊這個連結,會透過懸停預覽、右鍵選單,或電子郵件客戶端的撰寫視窗顯示地址。複製連結、儲存連結,或在瀏覽器開發者工具中檢查渲染後的 DOM,同樣會暴露這個地址。依賴 JavaScript 注入地址有其自身的問題:在指令碼被停用時可能失效、可能與內容安全政策衝突,還會多出一個靜態的、只含實體的錨點原本能避免的變動環節。數值參照讓結果維持成普通的 HTML,但這種單純也讓任何願意嘗試的程式,都能輕易解碼它。這個編碼器把這項限制寫在輸出結果旁邊,因為一個電子郵件混淆工具,不應該讓人對它究竟能防止多少垃圾郵件產生錯誤的信心。

該把這個錨點貼在哪裡,才能讓編碼保留下來

如果發布流程會把這些實體解碼回純文字,編碼的整個意義就消失了。有幾種內容系統會在儲存時重寫實體:一個所見即所得編輯器,可能會在頁面渲染之前,把 &#97; 解析回 a;一個 CMS 的清理器,可能會把 & 的序列正規化;一個伺服器端過濾器,可能會把這種編碼後的 mailto 標記為可疑,並把 href 值整個剝掉。這個編碼後的錨點,必須落在一個會儲存原始 HTML、並原封不動送回的環境中。

最安全的目的地是靜態 HTML 檔案、以純文字模式運作的佈景主題範本檔案、停用自動校正的自訂 HTML 區塊,以及會明確保留實體的程式碼注入欄位。有風險的目的地則是富文本編輯器、內建清理器的視覺化頁面產生器、會自動把電子郵件樣式轉成連結的部落格編輯器,以及任何會讓這段程式碼片段經過帶有連結縮短規則的 Markdown 處理器的流程。發布之後,在正式上線的頁面上檢視原始碼,並確認兩件事:可見文字與 href 中都不含字面上的 [email protected] 字元,而且這些實體仍然顯示為 &#97;,而不是解碼後的 a。如果你的 CMS 已經幫你把這些實體解碼掉了,混淆效果就沒了;如果它把這些實體重複跳脫成 &amp;#97;,訪客可能會看到實體文字本身,而不是地址。永遠要驗證真正公開的輸出結果,而不是只依賴複製下來的那段程式碼片段。

若想更完整地了解在套用這個編碼器之前,如何建立一個可正常運作的 mailto 連結,這篇關於 creating an email address link 的逐步指南,涵蓋了這個混淆工具所保留的底層標記慣例。

把這種編碼與伺服器端聯絡表單搭配,才能真正提高防禦力

這個編碼後的錨點,只是原始碼層面模糊化的其中一層。它讓地址對訪客而言仍然可以點擊,渲染成本為零,也能嚇阻最粗淺的地址蒐集者。但它本身並不會降低一個已經被鎖定的地址所遭受的濫用程度。要達到真正有意義的防禦力,需要把這個編碼後的錨點,與作用在編碼力所不及之處的措施搭配使用:一個會驗證輸入、套用速率限制、並對可疑送出內容使用驗證碼或同等挑戰機制的伺服器端聯絡表單;一個像 contact@ 或 info@ 這樣的可拋棄角色地址,在它出現在名單上時可以隨時輪替;能隔離明顯垃圾郵件的信箱供應商過濾規則;以及在收件端信箱上的信譽或回應率控管。編碼器在這整套機制中的角色,是讓地址不會被最簡單的字串搜尋抓到,同時把較重的流量交給更強的機制處理。

做法實際上做了什麼沒有做到什麼
只含實體的錨點(本工具)從渲染後的 HTML 原始碼中移除字面上的地址字元。停用指令碼的訪客仍能使用。無法阻擋現代爬蟲、mailto 連結的檢查,或有心的爬取者。
伺服器端聯絡表單完全隱藏目的地址,套用驗證與速率限制,過濾送出內容。單靠它本身,並不能給訪客一個可點擊的 mailto 連結。
以 JavaScript 注入的地址在指令碼執行之前,讓地址不出現在靜態原始碼中。在訪客停用指令碼時會失效,會與嚴格的 CSP 衝突,還會多出變動的環節。
搭配供應商過濾的角色地址用一個公開別名取代個人地址,並在接收端過濾送出內容。無法解決可見頁面原始碼被爬取的問題。

對大多數公開網站來說,實務上的組合是:用一個編碼後的錨點做輕量的聯絡連結,再搭配一個伺服器端表單處理真正重要的來信流量。這個編碼器很自然地扮演了這組搭配中「可見連結」的那一半,做到它實際上承諾的事,而不會誇大它無法保證的部分。

如果你還在考慮不同做法,How to Build Keyword Combinations Without Losing Any Pair 對此有詳細說明。