这 10 行比较字符串相等的代码给我整懵了,不信你也来看看

百家 作者:CSDN 2020-06-26 10:22:04

作者 | 码农唐磊
责编 | Aholiab
封图 | CSDN 付费下载自视觉中国
出品 | CSDN(ID:CSDNnews)

抱歉用这种标题吸引你点进来了,不过你不妨看完,看看能否让你有所收获。

先直接上代码:

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 版本(最开始吸引程序猿石头注意力的代码)如下:

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。

再想一下呢?

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

我们常常讲性能优化,从效率角度上讲,难道不是应该只要中途发现某一位的结果不同了(即为1)就可以立即返回两个字符串不相等了吗?(如上所示)。

这其中肯定有……

再细想一下呢?

结合方法名称 safeEquals 可能知道些眉目,与安全有关。

以前知道通过延迟计算等手段来提高效率的手段,但这种已经算出结果却延迟返回的,还是头一回!

我们来看看,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;
}

看注释知道了,目的是为了用常量时间复杂度进行比较。

但这个计算过程耗费的时间不是常量有啥风险?(脑海里响起了背景音乐:“小朋友,你是否有很多问号?”)

真相大白!

再深入探索和了解了一下,原来这么做是为了防止计时攻击(Timing Attack)。(也有人翻译成时序攻击)
计时攻击是边信道攻击(或称"侧信道攻击", Side Channel Attack, 简称SCA)的一种,边信道攻击是一种针对软件或硬件设计缺陷,走“歪门邪道”的一种攻击方式。
这种攻击方式是通过功耗、时序、电磁泄漏等方式达到破解目的。在很多物理隔绝的环境中,往往也能出奇制胜,这类新型攻击的有效性远高于传统的密码分析的数学方法(某百科上说的)。
这种手段可以让调用 safeEquals("abcdefghijklmn", "xbcdefghijklmn") (只有首位不相同)和调用 safeEquals("abcdefghijklmn", "abcdefghijklmn") (两个完全相同的字符串)的所耗费的时间一样。防止通过大量的改变输入并通过统计运行时间来暴力破解出要比较的字符串。
举个

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接