關於 Unicode 每個程式設計師應該知道的 5 件事

2017-11-27    分類:作業系統、程式設計開發、首頁精華0人評論發表於2017-11-27

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

上週末,曝出了山寨WhatsApp Android應用程式的新聞,看似由相同的開發者提供作為了官方應用程式。欺詐分子通過在開發者名字中包含unicode非輸出空格來避免驗證。在Play store的維護人員注意到之前,黑客已經欺騙了一百多萬人。

Unicode是一個令人難以置信的有用標準,它能使全世界的計算機、智慧手機和智慧手錶以同樣的方式顯示相同的資訊。不幸的是,它的複雜性使它成為了欺詐分子和惡作劇的金礦。如果谷歌這樣的巨頭都無法抵禦由Unicode引起的基本問題,那麼對於小公司來說,這或許就是一場看起來註定失敗的戰鬥。但是,這些問題大都圍繞一些漏洞出現。以下是所有開發人員需要了解的關於Unicode以防止欺詐的最重要的5件事情。

1.許多Unicode點不可見

Unicode有若干零寬度的程式碼點,例如零寬度聯結器(U+200D)和零寬度非聯結器(U+200C),這些用連字元號連線的工具都是暗示的(hints)。它們對螢幕外觀沒有可見的影響,但是它們會影響字串比較,這就是為什麼山寨WhatApp能夠躲過漏檢這麼久的原因。這些字元大多數都在常規的標點符號塊(從U+2000到U+206F)。一般來說,沒有理由允許任何人在識別符號中使用此標點符號塊的程式碼點,所以它們最不容易過濾。然而,在這個範圍之外還有一些其他的特殊程式碼是不可見的,比如蒙古文母音分隔符(U+180E)。

通常,使用Unicode對唯一性約束進行簡單的字串比較是很危險的。潛在的解決方法是限制識別符號允許的字符集以及可能被欺詐分子濫用的任何其他資料。不幸的是,這並不能完全解決問題。

2.許多程式碼點看起來非常相似

為了覆蓋世界上所有書面語言所使用的所有符號,Unicode不得不具有許多類似的字元,以至於人們無法區分這些字元,但計算機區分差異時則毫無問題。此問題導致了大量濫用Mimic——這是一個有趣的工具,用外觀類似的Unicode字元替換軟體開發中使用的常見符號,如冒號和分號。它可以造成程式碼編譯工具中的混亂,讓開發人員感到困惑。

符號外觀類似的問題遠遠不止是簡單的惡作劇而已。雖然有點奇怪被稱為是同態攻擊,但這些漏洞確實可能會導致嚴重的安全問題。2017年4月,一名安全研究人員通過混合來自不同字符集的字母,註冊了一個與apple.com非常相似的域名,甚至獲得了SSL證照。所有的主要瀏覽器都高高興興地顯示了SSL掛鎖,並將域名列為是安全的。

與混合可見和不可見字元類似,很少有任何理由允許在識別符號中使用混合字符集名稱,尤其是域名。大多數瀏覽器已採取措施懲罰混合字符集的域名,將它們顯示為十六進位制Unicode值,這樣使用者就不會輕易混淆。如果你要向使用者,例如在搜尋結果中,顯示識別符號,那麼考慮一些類似的方法以防止混淆。但是,這也不是一個完美的解決方案。某些域名,如sap.com或chase.com完全可以很容易地從非拉丁字符集的單個塊中構建起來。

Unicode聯盟釋出了一個容易混淆的字元列表,可用於自動檢查山寨貨。另一方面,如果你想尋找建立混淆的快速路徑,那麼請看Shapecatcher——這是一個奇妙的工具,它列出了看上去類似繪圖的Unicode符號。

3.規劃化其實不規範

規範化對於如使用者名稱等識別符號非常重要,可以幫助使用者雖以不同的方式輸入值,但能一致地處理它們。規範識別符號的常用方法是將所有內容都轉換為小寫,例如,確保JamesBond與jamesbond相同。

由於有如此多的相似字元和重疊集合,不同的語言或unicode處理庫可能會應用不同的規範化策略,這會潛在地開放安全風險,如果規範化在幾個地方完成的話。簡而言之,不要認為小寫變換在應用程式的不同部分中是一樣的。來自Spotify的Mikael Goldmann在他們的一個使用者發現劫持賬戶的一個方式之後,於2013年就此問題寫了一篇很讚的事件分析。攻擊者可以註冊其他人的使用者名稱(例如 ᴮᴵᴳᴮᴵᴿᴰ)的unicode變體,這些使用者名稱將被轉換為相同規範的帳戶名(bigbird)。應用程式的不同層次對字詞進行不同的規範化處理——允許使用者註冊惡意帳戶,但是會重置目標帳戶的密碼。

4.螢幕顯示長度和記憶體大小沒有關係

使用基本的拉丁文和大部分歐洲的字符集時,螢幕或紙張上的文字空間大致與符號數量成正比,與文字的記憶體大小大致也成正比。這就是為什麼EM和EN是流行的單位長度。然而通過Unicode,任何類似的假設都會變得危險。有一些可愛的符號,比如Bismallah Ar-Rahman Ar-Raheem(U+FDFD),此單個字元比大多數英文單詞都要長,因此很容易在網站上跳出假定的視覺封閉。這意味著基於字串字元長度的任何型別的換行或文字中斷演算法都可能輕易被愚弄。大多數終端程式需要固定寬度的字型,所以在其中一個顯示的話,你將在完全錯誤的地方看到結束引號。

對此有一個濫用就是zalgo文字生成器,在文字片段周圍新增圍繞著的垃圾,而這些垃圾將佔據更多的垂直空間。

當然,隱藏程式碼點的整個問題使得記憶體大小與螢幕長度無關,所以可以很好適合輸入域的東西可能足以炸燬資料庫領域。過濾非視覺字元以防止出現問題是不夠的,因為還有很多其他不佔用空間的例子。

結合拉丁字元(例如U+036B和U+036C)佔據上一個字母的空格,這樣你可以在單個文字行中寫入多行文字(’N\u036BO\u036C’生成NͫOͬ)。用來表示希伯來語聖經儀式吟誦的語調標記可以無限地堆疊在同一個視覺空間中,而這意味著它們可以輕易被濫用,會導致編碼大量資訊到螢幕上佔據單個字元的內容上。Martin Kleppe編碼了針對瀏覽器語調標記的《Conway’s Game of Life》的實現。檢視頁面的原始碼,很不錯。

5. Unicode不僅僅是被動資料

一些程式碼點旨在影響可輸出字元的顯示方式,這意味著使用者可以複製和貼上的不僅僅是資料——也可以輸入處理指令。一個常見的惡作劇是使用從右到左覆蓋(U+202E)來切換文字的方向。例如,用谷歌地圖搜尋Ninjas。查詢字串實際上會翻轉搜尋詞的方向,儘管頁面的搜尋欄位中顯示的是“ninjas”,但實際上它搜尋的是“sajnin”。

這個漏洞是如此受歡迎,以致於甚至成為了XKCD

混合資料和處理指令——可有效執行的程式碼——絕不是一個好主意,特別是如果使用者可以直接輸入的話。這對於包含在頁面顯示中的任何使用者輸入來說,都是一個大問題。大多數Web開發人員都知道通過刪除HTML標籤來清理使用者輸入,但輸入中的Unicode控制字元也需要注意。這是解決任何形式的髒話或內容過濾的簡單方法——只需要向後翻轉單詞,在開始處包含從右到左的覆蓋。

從右到左的編輯可能無法嵌入惡意程式碼,但如果不小心的話,可能會破壞內容或翻頁。防止這種情況的常用方法是將使用者提供的內容放入輸入欄位或文字區域,這樣處理指令不會影響頁面的其餘部分。

另一個關於顯示特別有問題的處理指令型別是字形變換選取器。為了避免為每個表情符號的每個顏色變體建立單獨的程式碼,Unicode允許使用變換選擇器將基本符號與顏色混合。白色旗幟、字形變換選取器和彩虹通常會產生彩虹色的旗幟。但並非所有的變換都是有效的。2017年1月,iOS unicode處理中的一個bug使得惡作劇者可以通過傳送特製訊息來遠端崩潰iPhone。訊息包含白色旗幟,字形變換選取器和一個零。這時,iOS CoreText會進入應急模式——嘗試選擇正確的變體,並使作業系統崩潰。此惡作劇作用於直接資訊、分組聊天,以及甚至共享聯絡人卡片。這個問題對iPad,甚至一些MacBook電腦也有影響。對此,我們幾乎束手無策。

類似的bug每隔幾年就會發生一次。2013年,阿拉伯字元處理的bug——可能會導致OSX和iOS崩潰——浮出水面。所有這些錯誤都深深埋藏在OS文字處理模組中,所以典型的客戶端應用程式開發人員根本無法阻止。

關於其他有趣的處理指令,請檢視GitHub上的Awesome Codepoints列表。對於Unicode造成的更多混亂,請查閱我寫的《Humans vs Computers》一書。

譯文連結:http://www.codeceo.com/article/5-things-every-programmer-know-about-unicode.html
英文原文:Five things everyone should know about Unicode
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章