在文字隱寫術中,每個隱藏的 UTF-8 位元組會精確地變成八個不可見的程式碼點,並由兩個標記框住,而這種擴充正是命令列管線與線上瀏覽器工具在傳遞結果時行為差異如此巨大的根本原因。瀏覽器將掩護文字當作即時的 Unicode 程式碼點來處理,因此不可見的酬載在你複製之前都會存活下來。相反地,shell 管線會將同一個字串導流經諸如 tr、sed、awk 和 sort 等工具,這些工具常會對預設可忽略字元進行正規化、刪除或重新編碼。螢幕上呈現的兩種文字看起來一模一樣,但在開始與結束標記之間的位元數,可能在檔案抵達目的地之前就已歸零。這種不對稱性正是為何對文字隱寫術的「命令列 vs. 線上」之爭,實務上的答案幾乎總是:使用瀏覽器工具來嵌入與萃取,然後只透過你已端到端測試過的通道來傳輸結果。

text steganography command line vs online
文字隱寫術:命令列與線上之比較

文字隱寫術如何將位元組嵌入看似普通的句子

Text Steganography 所使用的對應方式是一份有記載的零寬度慣例,並非某種混淆的密碼。兩個字元負責承載位元,另外兩個則負責標示邊界:

符號程式碼點在酬載中的角色
零寬度空格U+200B二進位 0
零寬度不接合符U+200C二進位 1
不可見分隔符U+2063開始標記
不可見加號U+2064結束標記

為了藏匿一則訊息,工具首先會將秘密字串編碼為一串 UTF-8 位元組,再把每個位元組展開成八個位元(最高位元優先),然後將每個 0 替換為 U+200B,每個 1 替換為 U+200C。接著,整段序列會以 U+2063 開始標記和 U+2064 結束標記包起來,而這個被框住的不可見區塊會插入掩護句子的第一個可見程式碼點之後。由於大多數字型將這四個程式碼點的推進寬度都設為零,渲染後的文字在視覺上仍保持掩護句的形狀,但底層的 Unicode 序列則變得長得多。

為何命令列管線會摧毀不可見的酬載

終端機工作階段是搬運不可見 Unicode 最糟糕的環境。問題並不在作業系統,而在於任何稍微複雜的命令列工作流程都會讓文字流經一連串的工具。常見的兇手包括:

  • 位元組篩選器。 tr -d、sed 和 awk 會以位元組或字元來運作,但幾乎沒有實作 Unicode Security Considerations 中所述的 Default_Ignorable_Code_Point 屬性。一個用來去除控制字元的迴圈,通常會把 U+200B 與 U+200C 連同 Tab 與換行字元一起刪掉。
  • 語系強制轉換。 在 C 或 POSIX 語系下執行管線會強制採單一位元組處理;任何不在現行代碼頁內的字元,在進入下一個階段之前就會被丟棄。
  • 行尾轉換。 改寫行尾的工具可能會對串流重新編碼,並悄悄刪除不在當前編碼內的程式碼點,包括標記字元。
  • 終端機渲染。 部分終端機模擬器在繪製儲存格時會去除預設可忽略字元,這表示即使串流本身原封不動,當你在終端機中選取並複製的那一刻,它就已經損壞了。
  • Shell 字詞切分。 將文字當作引數傳給 shell 管線,可能會把不可見字元切散到各個字詞之間,在任何工具執行之前就已破壞整個框住的區塊。

這些步驟都不會改變你在螢幕上看到的東西,這正是這種失效模式令人如此困惑的原因。終端機上的文字與檔案中的文字看起來一模一樣,但開始與結束標記之間的位元已經不見或順序錯亂,導致還原模式不是拒絕解碼就是回傳亂碼位元組。

線上 vs. 命令列:並排的優缺點

下表的比較聚焦於一個務實的問題:以 shell 為核心的工作流程能否保留零寬度酬載。就這項特定任務而言,除了可攜性之外,瀏覽器端在幾乎每一個面向都勝出。

特性命令列工作流程線上瀏覽器工具
保留 U+200B 與 U+200C幾乎不會,取決於管線中的每一個工具會,以即時程式碼點在 JavaScript 中處理
解碼時的 UTF-8 驗證必須自己撰寫腳本內建;格式錯誤的 UTF-8 會被拒絕,而不會被悄悄取代
建置成本安裝直譯器、撰寫輔助程式、測試邊緣情況開啟一個分頁
傳輸安全性每一道 pipe 與重新導向都是淨化風險直接從結果欄位複製到已測試的通道
解碼後可看見原始掩護文字必須手動重建與隱藏訊息一併回傳
離線使用可以,建置完成後即可可以,因為所有處理都留在瀏覽器內

最具決定性的一列是第一列。針對文字隱寫術,工具的價值取決於不可見字元能否在工作流程中存活。一款從不將掩護文字序列化通過篩選器的瀏覽器型工具是更安全的預設選擇,而該頁面本身也註明不會上傳任何資料,因此其隱私表現與本地腳本相當。

逐步隱藏與還原訊息

使用 Text Steganography 工具的完整隱藏—還原工作流程刻意設計得很短。每一步都讓可見的掩護文字保持可讀,讓你能驗證整個循環。

  1. 開啟隱藏模式,輸入一個看起來正常的掩護句子,例如 Meet me at the usual place.
  2. 在隱藏欄位中輸入秘密訊息。請控制在 10,000 個 UTF-8 位元組以內;表情符號與 CJK 文字每個字元會佔用多個位元組,因此可見字元數通常會少於位元組數。
  3. 產生隱寫字串並完整複製結果。不要重新打字,也不要讓它經過任何清理腳本。
  4. 透過一個你已事先驗證能保留預設可忽略字元的傳輸通道來傳送那段確切的字串。一個具備完整 Unicode 支援的純文字編輯器,通常比聊天用戶端、郵件閘道或社群網路編輯器更安全。
  5. 在接收端,切換到還原模式並原樣貼上該字串。工具會找出 U+2063 與 U+2064 標記,驗證每個酬載字元都是 U+200B 或 U+200C,要求位元數為八的倍數,然後將位元轉回位元組。
  6. 若解碼成功,頁面會同時顯示還原後的隱藏訊息與原始的掩護文字。將還原後的掩護文字與你送出的版本比對,以確認沒有位元在傳輸過程中遺失。
  7. 若解碼失敗,請將原始字串貼到程式碼點檢視器中,查看哪些不可見字元被傳輸過程去除或重新排序,然後改用其他通道重試。

通道保留能力:真正的決定因素

「命令列 vs. 線上」的問題常被框定為可用性的問題,但對零寬度隱寫術而言,決定因素其實是傳輸通道。一旦框住的酬載產生完畢,每個它經過的系統都潛藏著淨化的可能:

  • 社群網路會去除預設可忽略字元,以避免混淆字與同形異義字攻擊波及使用者。能完整存活通過大型平台的酬載屬於例外,非常態。
  • 郵件閘道會改寫 quoted-printable 或 MIME 編碼文字,並可能在重新編碼前,把 U+200B 與 U+200C 替換成佔位位元組。
  • 內容管理系統與所見即所得編輯器會將貼上的內容正規化為 Unicode 的子集,並在不留任何警告的情況下移除標記。
  • 螢幕截圖與列印版本根本不帶任何不可見的程式碼點,所以酬載在擷取的那一刻就已經遺失。
  • 部分作業系統上的剪貼簿管理員,在應用程式之間橋接時會去除零寬度字元。

這正是為何該工具說明書會明確指出:你必須只透過一個已端到端測試過的通道來複製產生的字串,並在確認送達成功後再進行還原。可行的模式是先透過預定通道送一則小型測試訊息,再放大規模。若想進一步比較 CLI 與線上工作流程在相關格式上的差異,Base64 decode command-line-vs-online guide 針對不同編碼探討了同一個傳輸問題。

限制、驗證,以及工具會拒絕的事

該工具會公開每一項限制,讓這項轉換是可以檢視的,而不是被隱藏的。隱藏訊息的上限是 10,000 個 UTF-8 位元組,掩護文字的上限則是 100,000 個程式碼點。由於每個隱藏的位元組會精確地變成八個不可見程式碼點加上兩個標記,一個滿載的 10,000 位元組酬載會展開為 80,002 個不可見程式碼點,插入在掩護句第一個字元之後。那個算式就是值得記住的公式:隱藏位元組數乘以 8,再加上 2 個標記,即等於加入掩護文字的不可見程式碼點總數。

還原模式會執行三項對「命令列 vs. 線上」抉擇而言相當關鍵的檢查:

  • 框線檢查。 它會定位第一對 U+2063 與 U+2064。若掩護文字中已含有任一標記,嵌入將被拒絕,因為酬載邊界會變得模稜兩可。
  • 位元檢查。 標記之間的每個字元都必須是 U+200B 或 U+200C,且總數必須為八的倍數。
  • UTF-8 檢查。 解碼後的位元組序列必須是合法的 UTF-8。無效序列會以錯誤形式回傳,而不是悄悄替換成替代字元——而這正是大多數 Unix 管線最終會做的事。

整個循環同樣會被稽核:ASCII、CJK、表情符號、Tab、換行、單一程式碼點的掩護、空輸入、保留標記、缺少酬載、不完整的位元組——這些情況都會同時回傳還原後的隱藏文字與原始的掩護文字。正是這項稽核讓瀏覽器端的實作得以作為可信賴的參考;它證明了該慣例能在其自身的平台上完成完整的循環,獨立於任何可能在背後悄悄竄改結果的外部傳輸機制。

若你需要機密性、真實性或完整性,請把隱藏訊息當作純文字看待。這套對應方式有文件記載且極易被察覺,因此任何知道這套慣例的人都能讀取它,而任何掌控通道的人都能改寫它。若要進行持久且可驗證的資料交換,請改用可見的編碼方式或經過驗證的檔案格式。若是為了學習 Unicode 如何承載非渲染資料、製作謎題,或檢查下游系統是否會淨化不可見的程式碼點,Text Steganography 工具是一個快速且可檢視的參考實作。

若你正在權衡各種選項,Convert Text to a Binary File With 8-Bit UTF-8 Bytes 對此有詳細說明。