這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看

這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看

碼農唐磊 程序猿石頭 java

這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看

抱歉用這種標題吸引你點進來了,不過你不妨看完,看看可否讓你有所收穫。(有收穫,請評論區留個言,沒收穫,下週末我直播吃**,哈哈,這你也信)安全

補充說明:微信公衆號改版,對各個號主影響還挺大的。目前從後臺數據來看,對我影響不大,由於我這反正都是小號圖片閱讀量自己就少的可憐,真相了,圖片(剛從交流羣學會的表情)。性能優化

先直接上代碼:微信

boolean safeEqual(String a, String b) {
   if (a.length() != b.length()) {
       return false;
   }
   int equal = 0;
   for (int i = 0; i < a.length(); i++) {
       equal |= a.charAt(i) ^ b.charAt(i);
   }
   return equal == 0;
}

上面的代碼是我根據原版(Scala)翻譯成 Java的,Scala 版本(最開始吸引程序猿石頭注意力的代碼)以下:cookie

def safeEqual(a: String, b: String) = {
  if (a.length != b.length) {
    false
  } else {
    var equal = 0
    for (i <- Array.range(0, a.length)) {
      equal |= a(i) ^ b(i)
    }
    equal == 0
  }
}

剛開始看到這段源碼感受挺奇怪的,這個函數的功能是比較兩個字符串是否相等,首先「長度不等結果確定不等,當即返回」這個很好理解。
再看看後面的,稍微動下腦筋,轉彎下也能明白這其中的門道:經過異或操做1^1=0, 1^0=1, 0^0=0,來比較每一位,若是每一位都相等的話,兩個字符串確定相等,最後存儲累計異或值的變量equal一定爲 0,不然爲 1。session

再細想一下呢?

for (i <- Array.range(0, a.length)) {
  if (a(i) ^ b(i) != 0) // or a(i) != b[i]
    return false
}

咱們經常講性能優化,從效率角度上講,難道不是應該只要中途發現某一位的結果不一樣了(即爲1)就能夠當即返回兩個字符串不相等了嗎?(如上所示)。
這其中確定有……
這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看ide

再再細想一下呢?


結合方法名稱 safeEquals 可能知道些眉目,與安全有關。函數

本文開篇的代碼來自playframewok 裏用來驗證cookie(session)中的數據是否合法(包含簽名的驗證),也是石頭寫這篇文章的由來。性能

之前知道經過延遲計算等手段來提升效率的手段,但這種已經算出結果卻延遲返回的,仍是頭一回!
咱們來看看,JDK 中也有相似的方法,以下代碼摘自 java.security.MessageDigest:優化

public static boolean isEqual(byte[] digesta, byte[] digestb) {
   if (digesta == digestb) return true;
   if (digesta == null || digestb == null) {
       return false;
   }
   if (digesta.length != digestb.length) {
       return false;
   }

   int result = 0;
   // time-constant comparison
   for (int i = 0; i < digesta.length; i++) {
       result |= digesta[i] ^ digestb[i];
   }
   return result == 0;
}

看註釋知道了,目的是爲了用常量時間複雜度進行比較。
但這個計算過程耗費的時間不是常量有啥風險?(腦海裏響起了背景音樂:「小朋友,你是否有不少問號?」)
這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看

真相大白


再深刻探索和了解了一下,原來這麼作是爲了防止計時***(Timing Attack)。(也有人翻譯成時序***)
這 10 行比較字符串相等的代碼給我整懵了,不信你也來看看

計時***(Timing Attack)


計時***是邊信道***(或稱"側信道***", Side Channel Attack, 簡稱SCA) 的一種,邊信道***是一種針對軟件或硬件設計缺陷,走「歪門邪道」的一種***方式。這種***方式是經過功耗、時序、電磁泄漏等方式達到破解目的。在不少物理隔絕的環境中,每每也能出奇制勝,這類新型***的有效性遠高於傳統的密碼分析的數學方法(某百科上說的)。這種手段可讓調用 safeEquals("abcdefghijklmn", "xbcdefghijklmn") (只有首位不相同)和調用 safeEquals("abcdefghijklmn", "abcdefghijklmn") (兩個徹底相同的字符串)的所耗費的時間同樣。防止經過大量的改變輸入並經過統計運行時間來暴力破解出要比較的字符串。舉個

相關文章
相關標籤/搜索