Могу ли я использовать Object # hashCode для хранения хэша пароля? - PullRequest
8 голосов
/ 12 августа 2010

Для сохранения файла я определил следующий метод

public int encrypt(String fileName, String password) {
   return (fileName.concat(password)).hashCode();
}

Возвращает хеш-значение, которое хранится в файле. Всякий раз, когда пользователь хочет получить доступ к файлу, он вводит пароль и, если генерируется тот же хеш, он может получить доступ к файлу.

Полагаю, это не совсем безопасно, но насколько это безопасно? Насколько велика вероятность того, что String # hashCode сгенерирует один и тот же хеш с двумя разными входами?

EDIT:

В соответствии с вашими ответами я изменил код:

public String encrypt(String password) {
        String hash = "";
        try {
            MessageDigest md5 = MessageDigest.getInstance("SHA-512");
            byte [] digest = md5.digest(password.getBytes("UTF-8"));
            hash = Arrays.toString(digest);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hash;
    }

Так что теперь должно быть лучше ??

Ответы [ 8 ]

17 голосов
/ 12 августа 2010

Это плохая идея - вы должны использовать обычный криптографический хеш, такой как SHA-1, так же, как говорит NullUserException.

Однако, будет переносимым - документы для String.hashCode() явно указывают алгоритм. Любая JRE, правильно реализующая документы, должна давать тот же хэш-код. Однако из-за того, как работает алгоритм hashCode(), довольно легко найти строку, которая сгенерирует любой конкретный хеш-код - даже тот, который начинается с определенного префикса - поэтому злоумышленник, который знал хеш, может очень легко атаковать ваше приложение. , Криптографические хеши разработаны так, чтобы затруднить создание ключа, соответствующего определенному хешу.

5 голосов
/ 12 августа 2010

String.hashCode не подходит для хеширования паролей. Вместо этого вам нужен криптографический хеш.

String.hashCode разработан для очень быстрого вычисления. Его основное использование для ключа в хэш-таблице. Для этого использования случайное столкновение не является проблемой. Криптографические хэши вычисляются медленнее, но по определению никто не знает, как создавать коллизии для хорошей криптографии.

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

Криптографические хеши доступны в стандартной библиотеке Java через java.security.MessageDigest .

ДОБАВЛЕНО : Есть еще одно осложнение: плохая идея напрямую хэшировать пароль. Причина в том, что злоумышленник может использовать все вероятные пароли (например, слова в словарях, имена людей и т. Д.). Стандартное решение этой проблемы - объединить пароль со строкой random , называемой * 1020. * salt перед вычислением хэша: вы делаете что-то вроде sha.digest((salt+password).getBytes()). Соль делает нецелесообразным для злоумышленника предварительное вычисление всех хэшей вероятных паролей.

Обычно соль генерируется случайным образом, когда пользователь выбирает свой пароль, и она хранится рядом с хэшем пароля в пользовательской базе данных, но из того, что вы показываете в своей схеме, такого нет. Учитывая ваш дизайн, было бы разумно использовать имя файла в качестве соли: fileName.concat(encrypt(fileName + password)).

5 голосов
/ 12 августа 2010

Обычно плохая идея полагаться на некриптографические функции для обеспечения безопасности. Поскольку вы никогда не можете быть уверены, какая реализация используется (и будет использоваться в будущем) для вычисления хеш-кода строки, вы должны предпочесть алгоритм криптографического безопасного хеш-кода. Я бы посоветовал использовать SHA-1 или SHA-256. http://www.bouncycastle.org/ имеет реализации для многих алгоритмов хеширования.

2 голосов
/ 12 августа 2010

Это не так сложно, как вы думаете, для хэширования данных, и лучше использовать настоящий алгоритм хэширования.Если у вас есть байтовый массив, содержащий пароль, вы можете просто сделать что-то вроде этого.Если вы получаете байтовый массив из строки, не забудьте указать кодировку (то есть UTF-8) при вызове getBytes ();

Вот простой пример использования MD5.

2 голосов
/ 12 августа 2010

Честно говоря, я не знаю, насколько устойчива к коллизиям Java hashCode().Если бы я угадал, я бы сказал, не очень.Я проверял это раньше и обнаружил пару столкновений после нескольких сотен тысяч входов.

Поскольку здесь вы имеете дело с паролями, вам действительно следует использовать криптографический хеш, такой как SHA1.

1 голос
/ 12 августа 2010

Вот реализация String.hashCode ():

s [0] * 31 ^ (n-1) + s [1] * 31 ^ (n-2) +... + s [n-1]

Публично доступно здесь ...

Это фактически не зависит от виртуальной машины и не было Java-версией-зависимый в прошлом.Реализация осталась прежней.

Безопасность столкновений в порядке ИМХО, однако по понятным причинам плохая идея использовать ее в криптографических целях.

1 голос
/ 12 августа 2010

Я бы обеспокоен тем, что этот код не является переносимым. Нет гарантии, что одна JVM создаст то же значение хеш-функции, что и другая JVM Это кажется очень рискованным.

0 голосов
/ 12 августа 2010

проблема # 1 в том, что хеш составляет всего 32 бита.это слишком коротко.ребенок с бейсиком может сломать его за секунду.

md5 имеет длину 128 битов, и теперь он считается слабым

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...