Сравнение строк Java с использованием побитового xor

я наткнулся на приведенный ниже фрагмент кода в коде продукта. Он использует побитовое XOR для сравнения строк. Это лучше, чем 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;
  }

для контекста приравниваемые строки являются маркерами аутентификации.

1 ответов


Это общая реализация функции сравнения строк, которая неуязвима для атак синхронизации.

короче говоря, идея состоит в том, чтобы сравнить все символы каждый раз, когда вы сравниваете строки, даже если вы обнаружите, что любой из них не равны. В" стандартной " реализации вы просто разбиваете первую разницу и возвращаете false.

Это не безопасно, потому что он дает информацию о сравниваемых строк. Особенно если левой боковой струны секрет хотите сохранить (например, пароль), а правая строка-это то, что предоставляет пользователь, небезопасный метод позволяет хакеру раскрыть ваш пароль с относительной легкостью, многократно пробуя разные строки и измеряя время отклика. Чем больше символов в двух строках идентичны, тем больше "незащищенной" функции потребуется для их сравнения.

например, Сравнение "1234567890" и "0987654321" с использованием стандартного метода приведет к выполнению только одного сравнение первого символа и возврат false, начиная с 1!=0. С другой стороны, сравнение "1234567890" с "1098765432" приведет к выполнению 2 операций сравнения, потому что первые равны, вам нужно сравнить вторые, чтобы найти, что они разные. Это займет немного больше времени, и это измеримо, даже когда мы говорим об удаленных вызовах.

Если вы делаете N атак с N различными строками, каждая из которых начинается с другого символа, вы должны увидеть один из результатов принятия доли milisecond больше, чем остальное. Это означает, что первый символ одинаков, поэтому функция должна занять больше времени, чтобы сравнить второй. Промойте и повторите для каждой позиции в строке, и вы можете взломать секретные порядки величины быстрее, чем грубая сила.

предотвращение такой атаки является точкой такой реализации.

Edit: как старательно указано в комментарий Марк Rotteveel, это реализация по-прежнему уязвима для атаки времени, которая направлена на выявление длины строки. Тем не менее, это не проблема во многих случаях (либо вам все равно, что злоумышленник знает длину, либо вы имеете дело со стандартными данными, и любой может знать длину в любом случае, например, какой-то хэш известной длины)