Как получить соль из пароля и использовать ее для проверки пользователя?

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

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

Если я правильно понял процесс такой:

  1. Пользователь вводит пароль
  2. Случайное создание соли
  3. Хэш-пароль и соль
  4. Сохранить результат в базе данных

Но как мне восстановить соль, когда пользователь пытается войти в систему?

  1. Пользователь вводит свой пароль
  2. Я каким-то образом добавляю его собственную уникальную случайно сгенерированную соль
  3. Перемешать их обоих вместе
  4. Сравните его с хэшированным паролем, хранящимся в базе данных.

В нескольких вопросах, которые я нашел, один из ответов заключался в том, чтобы хранить случайно сгенерированную соль в базе данных. Но я думал, что вся цель соления состоит в том, чтобы быть более безопасным, если злоумышленник получит доступ к моей БД, он увидит поля «соли», и даже если мои пароли зашифрованы, он получит легкий доступ к учетным записям.

В других ответах говорилось, что «соль» добавляется к паролю при использовании crypt(), поэтому нет необходимости хранить ее в отдельном поле. У меня вопрос, как мне получить к нему доступ? Есть ли какая-то функция, которая делает это, и я полностью отсутствует?


person Ant100    schedule 23.01.2014    source источник
comment
хранить соль в БД, это НЕ определяет безопасность, делая это, раздельно или с паролем, ваш звонок, я сделал и то, и другое   -  person    schedule 24.01.2014
comment
@ Дагон, не так ли? Конечно, смысл соли в том, чтобы добавить в хеш что-то неизвестное, разве простое размещение ключа рядом с ним не делает его бесполезным?   -  person Niet the Dark Absol    schedule 24.01.2014
comment
никакая соль не останавливает атаки радужного стола, зная соль, вы должны воссоздать всю радужную таблицу с каждой солью   -  person    schedule 24.01.2014
comment
Это не так? Ладно, так проще. Мне интересно, как получить предварительно добавленную соль из хешированного пароля. Вы знаете, как это сделать?   -  person Ant100    schedule 24.01.2014
comment
Вы не получаете его из хэша, вы сохраняете его в отдельном поле.   -  person Digital Chris    schedule 24.01.2014
comment
PHP имеет встроенный отличный механизм паролей, который обрабатывает все эти вещи за вас (и объединяет хэш и соль в одно поле): php.net/manual/en/ref.password.php   -  person Digital Chris    schedule 24.01.2014
comment
@DigitalChris, вы не храните соль отдельно. Если вы все делаете правильно (см. ответ jterry), он сохраняется прямо в хеше.   -  person Mike    schedule 24.01.2014
comment
Нет, дело не в хэше, и это многих смущает. Реализация PHP просто хранит хеш и соль вместе в одном поле, но также уместно иметь поле соли.   -  person Digital Chris    schedule 24.01.2014
comment
@DigitalChris, если вы храните его отдельно, вы либо не используете функции хеширования паролей, на которые вы ссылались выше, либо используете какое-то средство разделения строк для его разделения. В любом случае, все, что вы делаете, подвержено ошибкам.   -  person Mike    schedule 24.01.2014
comment
@Майк, я заблудился, так что мне делать? :С   -  person Ant100    schedule 24.01.2014
comment
Я вижу, что ты говоришь. да. есть два варианта: 1 — позволить PHP обрабатывать соль для вас. Однако, если вы используете стандартную схему пароля, у вас будет соль в отдельном поле; наличие одного поля делает его удобным для пользователя и является частью магии password_hash().   -  person Digital Chris    schedule 24.01.2014
comment
@DigitalChris, насколько я знаю, реализация PHP основана на Unix Crypt, и хэши совместимы друг с другом. Оба создадут строку с алгоритмом хэширования, солью и фактическим хешированным паролем, объединенными вместе.   -  person Mike    schedule 24.01.2014
comment
Ant100 — если вы все еще не уверены: поскольку вы используете более старый PHP, используйте PHPass. При обновлении вы можете использовать password_hash().   -  person Digital Chris    schedule 24.01.2014
comment
В этом ответе я попытался объяснить, как можно извлечь соль из хеш-значения. Функция crypt извлечет это автоматически.   -  person martinstoeckli    schedule 24.01.2014
comment
@Mike, вы думаете о crypt(), который использует отдельно хранящуюся соль для расшифровки.   -  person Digital Chris    schedule 24.01.2014
comment
@DigitalChris password_hash() основан на crypt. Ознакомьтесь с кодом из библиотеки совместимости ircmaxell.   -  person Mike    schedule 24.01.2014
comment
@Mike ... да ... он основан на крипте и использует крипту, но добавляет НОВЫЕ вещи, такие как унифицированный хеш / соль в одном поле и автоматическое создание соли. Они не одинаковы. Это стало довольно эзотерическим и бесполезным для Ant100, который просто хочет реализовать схему паролей, поэтому это будет последний комментарий здесь.   -  person Digital Chris    schedule 24.01.2014
comment
Спасибо за вашу помощь. В конце концов я решил добавить новое поле под названием «соль» в базу данных и сохранить там соль. Я храню его как двоичный тип (16), знаете ли вы, какой тип должен быть у моего хешированного пароля для mysql?   -  person Ant100    schedule 24.01.2014
comment
@ Ant100, придерживайтесь того, что говорят jterry и DigitalChris, и используйте либо password_hash, либо PHPass (ссылки выше). Не применяйте свои собственные механизмы хеширования паролей, потому что вы ПОЛУЧИТЕ их неправильно. Пусть этим займутся люди, которые умнее нас с вами. Отдельно хранить соль не нужно. Он содержится в выходной строке. См. этот вопрос для как хранить все это в вашей базе данных.   -  person Mike    schedule 24.01.2014
comment
@Mike, спасибо, я буду использовать PHPass! Я на самом деле проверяю это, и выглядит довольно просто для реализации. Однако один быстрый вопрос: нигде он не запрашивает у меня соль, значит, он реализован автоматически? -- Неважно, просто прочитайте, что это так. Потрясающий!   -  person Ant100    schedule 24.01.2014


Ответы (3)


Вы храните соль в своей базе данных вместе с хешированным паролем, то есть hash(salt+password).

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

Что такое атака с помощью радужного стола?

Давайте предположим общий алгоритм хеширования, hash(f).

Я, как злоумышленник, предварительно вычисляю общие пароли (f) и их хеши (hash(f)). Теперь, когда я получу вашу несоленую базу данных хэшей, мне просто нужно просмотреть вашу базу данных на предмет хэшей, которые соответствуют моей предварительно рассчитанной таблице (таблице радуги).

Например, если в моей радужной таблице хранятся f = qwerty, hash(f) = someRandomHash, я просматриваю вашу базу данных для someRandomHash и, как только нахожу, знаю, что пароль пользователя — qwerty.

Однако, если вы посолили свои пароли, когда пользователь установил свой пароль как qwerty, вы вычислили его хэш как hash('saltqwerty), что означает, что вы вычислили его хэш не как someRandomHash, а как someRandomSaltedHash. Это делает мой радужный стол совершенно бесполезным.

У меня не осталось выбора, кроме как взломать ваш стол. Я знаю соль, но не знаю пароль, поэтому мне приходится вычислять hash(salt+password) для каждой возможной перестановки и комбинации пароля. При достаточно медленном алгоритме хеширования это может занять столетия (в худшем случае).

Как вы входите в систему?

Пользователь отправляет свой user_id и пароль. Вы запрашиваете в базе данных соль для этого пользователя. Затем вы вычисляете hash(salt+password) и сравниваете с хешем, хранящимся в вашей базе данных.

person xbonez    schedule 23.01.2014
comment
да, я хэширую и соль, и пароль. Но когда пользователь входит в систему, он будет только вводить пароль, как мне получить соль и добавить ее? - person Ant100; 24.01.2014
comment
Отредактированный ответ, чтобы объяснить, что - person xbonez; 24.01.2014
comment
Большое спасибо за объяснение! Соль тогда сберегу в отдельном поле. Является ли crypt() достаточно хорошим хешем? - person Ant100; 24.01.2014
comment
Это не радужная таблица, а простая таблица поиска. - person Gumbo; 24.01.2014
comment
@Gumbo: это все еще радужный стол, хотя и очень неэффективный (в космосе). Со страницы википедии: цель состоит в том, чтобы предварительно вычислить структуру данных, которая при любом выходе h хеш-функции может либо найти элемент p в P, такой что H(p) = h, либо определить, что такого p нет в P. Самый простой способ сделать это - вычислить H (p) для всех p в P. Таблица поиска будет структурой данных в памяти, такой как массив, хэш-таблица и т. Д. - person xbonez; 24.01.2014

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

Из-за очевидной массовой путаницы, если вы можете использовать PHP v5.5.0 или выше, хранение паролей стало значительно проще с использованием password_hash и password_verify.

В качестве дополнительного преимущества эти функции не требуют наличия в базе данных отдельных полей password и salt — вы можете просто сохранить возвращаемое значение password_hash и использовать password_verify с открытым текстовым паролем для проверки.

person jterry    schedule 23.01.2014
comment
Существует библиотека совместимости, позволяющая сделать эти функции доступными для php ‹ 5.5 по ссылкам выше. - person Mike; 24.01.2014
comment
Спасибо, я читал об этом, к сожалению, я считаю, что текущий проект использует PHP 5.2 или PHP 5.3. - person Ant100; 24.01.2014
comment
Обязательно ознакомьтесь со ссылками на страницы руководств по PHP в соответствии с комментарием @Mike... они прикроют вам версии ‹ 5.5.0! - person jterry; 24.01.2014

Я мало что знаю о БД с высоким уровнем безопасности, но как насчет этого?:

hashedPassword = hash(UsurID+GivenPassword)

Таким образом, во время входа в систему вы сначала получаете логин пользователя и его идентификатор, а затем заданный пароль для сравнения с хешированным паролем, который уже находится в БД. Как я уже сказал, я не знаю, повысит ли это безопасность, но, по крайней мере, все пароли будут разными, не так ли?

В любом случае, я тоже еще учусь.

person Jorge Santos    schedule 23.01.2014
comment
Не давайте таких ненадежных советов в ТАК, пожалуйста. - person Georgi-it; 08.09.2015