如何防範 Unicode 雙向文字與同形異義字元造成的安全問題?
題目與使用場景
程式碼審查工具、帳號系統或網域顯示中,攻擊者提交了視覺上相似的字元,或使用雙向控制字元改變閱讀順序。請說明邏輯順序與顯示順序的差異,解釋混淆檢測與限制策略,並給出不破壞正常多語言文字的處理流程。
面試官考察什麼
- 是否理解 Unicode 雙向演算法只影響顯示順序,底層邏輯順序仍保持不變。
- 能否區分雙向覆寫、隔離字元、腳本混合與同形異義檢測。
- 是否知道 UTS #39 的 skeleton 是檢測中間值,不應直接顯示或跨 Unicode 版本重複使用。
- 能否把輸入驗證、顯示、稽核、權限比較與升級遷移分開設計。
作答前的澄清問題
先確認對象是原始碼、登入識別、國際化網域、搜尋文字或一般評論;確認是否允許多腳本、目標語言與顯示端支援;再確認檢測結果是阻擋、人工複核、警告還是僅記錄。也要確認 Unicode 資料版本、保留原文要求與誤報容忍度。
30 秒回答框架
Unicode 文字有邏輯順序與顯示順序。UAX #9 的雙向演算法會依字元方向屬性重排顯示,但雙向控制字元不改變比較、解析或數字分析。安全上要限制危險控制字元,依 UTS #39 做腳本與 confusable 檢測;skeleton 只作為同一版本下的中間比較鍵,不能當顯示文字。系統保留原文,產生版本化診斷結果,在高風險識別上阻擋或複核,並用固定策略驗證權限比較。
分步驟深入解答
1. 先分清邏輯順序與顯示順序
阿拉伯文、希伯來文與數字混排時,UAX #9 依強、弱與中性方向類型計算顯示順序。RLO、LRO 等覆寫字元會強制方向,隔離字元則限制內部文字對外部段落的影響。顯示重排不改變記憶體中的碼點順序,也不應被當作解析或比較規則。
2. 識別雙向控制與腳本混合風險
原始碼、檔名、帳號名等結構化識別通常不需要任意方向控制字元。輸入層可拒絕或標記 Bidi_Control;顯示層顯示轉義標記或明確方向邊界。腳本混合策略應依業務允許的語言集合定義,不能簡單把所有非 ASCII 字元判為惡意。
3. 使用版本化的 confusable 檢測
UTS #39 提供 confusables 資料與 skeleton 機制,用來判斷視覺混淆。confusability 受字型、腳本與上下文影響,不是絕對等價關係。保存原文、Unicode 版本、腳本分析與檢測結果;升級資料後重新計算並審查新增衝突,權限判斷仍使用協定規定的精確比較規則。
高品質示範回答
我會先依欄位定義風險。對原始碼、使用者名稱與網域這類結構化識別,保存原文並限制允許腳本與方向控制字元;對一般多語言正文,則保留合法的雙向排版能力。UAX #9 只決定顯示順序,雙向控制字元不應改變解析、比較或數字分析,因此稽核工具必須同時顯示邏輯碼點順序與可見渲染。檢測階段使用 UTS #39 的限制等級、腳本混合規則與 confusables 資料;skeleton 是同一 Unicode 資料版本內的中間鍵,不能直接顯示,也不能跨版本永久重用。高風險欄位出現 RLO、異常腳本組合或與既有識別衝突時進入阻擋或人工複核,普通文字則記錄警告。比較與授權使用欄位協定定義的規範化、大小寫與編碼規則,不能把視覺相似當成相等。升級 Unicode 資料時批次重算並稽核衝突,確保變更可追蹤且可回復。
常見錯誤
- 把顯示順序誤認為字串的實際儲存順序。
- 說刪除所有由右至左字元就能解決安全問題,誤傷正常阿拉伯文或希伯來文。
- 把 skeleton 當成穩定雜湊、顯示值或跨版本協定欄位。
- 只檢查 ASCII,忽略字型、腳本、組合標記與上下文造成的混淆。
- 用視覺相似判斷權限、簽章或唯一性,跳過欄位的精確比較規則。
追問及應對
為什麼不能在所有輸入上刪除雙向控制字元?
控制字元確實可能用於欺騙,但合法文件與排版也可能需要方向控制。應依欄位風險與目標平台決定阻擋、轉義、隔離或告警,並保留可稽核證據。
skeleton 結果可以直接作為使用者名稱嗎?
不可以。它是檢測用的中間形式,且會隨 Unicode 資料版本變化。使用者名稱仍需保留原文與協定定義的比較鍵,skeleton 只用於衝突診斷或人工複核。
如何降低多語言場景的誤報?
先定義允許的語言與腳本集合,再結合 CLDR 語言資料、欄位上下文與人工複核。對評論正文採用告警,對登入識別、網域與程式碼識別採用更嚴格的限制。