一个字符串比较函数引发的思考

最近在论坛上看看别人写的代码,其中有一个函数吸引了我的注意,直接上源码

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;
}

 

 很简单的一个功能,比较两个字符串是否相等

如果是我,我会怎么写

1 简单版

    /**
     * 简单版 比较每一位是否相等
     */
    public boolean myEquals1(String str1, String str2) {
        // 如果位数不相等,直接返回 false
        if (str1.length() != str2.length()) {
            return false;
        }
        for (int i = 0; i < str1.length(); i++) {
            if (str1.charAt(i) != str2.charAt(i)) {
                return false;
            }
        }
        return true;
    }

2 优化

计算机中数据在内存中是以二进制存储的,对二进制的直接操作,如位运算,效率会大大提高

    /**
     * 位运算
     */
    public boolean myEquals2(String str1, String str2) {
        // 如果位数不相等,直接返回 false
        if (str1.length() != str2.length()) {
            return false;
        }
        for (int i = 0; i < str1.length(); i++) {
            if ((str1.charAt(i) ^ str2.charAt(i)) != 0) {
                return false;
            }
        }
        return true;
    }

至此,自我感觉非常良好,感觉什么都考虑到了,但是和源码一对比,发现了猫腻

equal |= a.charAt(i) ^ b.charAt(i);

有一位不相等,就说明两个字符串不相等,直接退出即可,这个逻辑没毛病呀

那难道是他们的代码有问题?

查看源图像

后来看了大佬的解释才明白,这是为了防止 Timing Attack

时序攻击属于侧信道攻击/旁路攻击(Side Channel Attack),侧信道攻击是指利用信道外的信息,比如加解密的速度/加解密时芯片引脚的电压/密文传输的流量和途径等进行攻击的方式,一个词形容就是“旁敲侧击”。

举一个最简单的计时攻击的例子,某个函数负责比较用户输入的密码和存放在系统内密码是否相同,如果该函数是从第一位开始比较,发现不同就立即返回,那么通过计算返回的速度就知道了大概是哪一位开始不同的,这样就实现了电影中经常出现的按位破解密码的场景。密码破解复杂度成千上万倍甚至百万千万倍的下降。

最简单的防御方法是:“发现错误的时候并不立即返回,而是设一个标志位,直到完全比较完两个字符串再返回”。

 

 

所以说我们在读源码的时候,思考别人是怎么设计的,为什么这么设计,我让就像我一样,自取其辱啦。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值