【问题标题】:Java string comparison using bitwise xor使用按位异或进行 Java 字符串比较
【发布时间】:2017-11-14 22:46:03
【问题描述】:

我在产品代码中遇到了以下代码 sn-p。它使用按位异或进行字符串比较。这比String.equals(Object o) 方法好吗?作者想在这里达到什么目的?

private static boolean compareSecure(String a, String b)
  {
    if ((a == null) || (b == null)) {
      return (a == null) && (b == null);
    }
    int len = a.length();
    if (len != b.length()) {
      return false;
    }
    if (len == 0) {
      return true;
    }
    int bits = 0;
    for (int i = 0; i < len; i++) {
      bits |= a.charAt(i) ^ b.charAt(i);
    }
    return bits == 0;
  }

对于上下文,被等同的字符串是身份验证令牌。

【问题讨论】:

  • 这是比较字符串的一种较慢的方式,因为它必须始终比较所有字符。它并不比String.equals() 更安全。
  • @FredK 不正确。重新阅读第一个if 语句。这实际上可能是对String.equals() 的唯一改进:它是空安全的,也许这就是“安全”部分。在 Java 7+ 中,您可以使用 Objects.equals() 获得相同的 null 安全行为
  • 这比标准的equals 不安全。
  • @Zong 没有碰撞问题。它使用的是bits |=,而不是bits ^=。如果任意两个字符不相等,则设置一个或多个位,并保持设置直到结束。
  • 这个比较的目的是尽量不受字符串内容的影响,以防止计时攻击(正常的字符串比较会泄露关于等前缀有多长的信息)。

标签: java bitwise-operators bitwise-xor


【解决方案1】:

这是字符串比较函数的常见实现,不受定时攻击。

简而言之,这个想法是每次比较字符串时都比较所有字符,即使你发现其中任何一个不相等。在“标准”实现中,您只需打破第一个差异并返回 false。

这是不安全的,因为它会泄露有关比较字符串的信息。具体而言,如果左侧字符串是您要保留的秘密(例如密码),而右侧字符串是用户提供的内容,则不安全的方法允许黑客通过反复尝试相对轻松地发现您的密码输出不同的字符串并测量响应时间。 两个字符串中相同的字符越多,“不安全”函数就越需要比较它们。

例如,使用标准方法比较“1234567890”和“0987654321”将导致仅对第一个字符进行一次比较并返回 false,因为 1!=0。另一方面,比较“1234567890”和“1098765432”会导致执行2个比较操作,因为第一个是相等的,你必须比较第二个才能发现它们不同。这会花费更多时间,而且是可以衡量的,即使我们正在谈论远程调用。

如果您使用 N 个不同的字符串进行 N 次攻击,每个字符串都以不同的字符开头,您应该会看到其中一个结果比其余的多出几分之一毫秒。这意味着第一个字符相同,因此该函数必须花费更多时间来比较第二个字符。冲洗并重复字符串中的每个位置,您可以比蛮力更快地破解秘密数量级。

防止此类攻击是此类实施的重点。

编辑:正如 Mark Rotteveel 在comment 中认真指出的那样,此实现仍然容易受到旨在揭示字符串长度的定时攻击。在许多情况下这仍然不是问题(您不关心攻击者知道长度,或者您处理标准数据并且任何人都可以知道长度,例如某种已知长度的哈希)

【讨论】:

  • 问题中的代码仍然容易受到定时攻击以找出字符串的长度。
猜你喜欢
  • 1970-01-01
  • 2017-02-20
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
  • 2012-08-31
  • 2011-10-19
相关资源
最近更新 更多