Безопасный хэш и соль для паролей PHP

В настоящее время говорят, что MD5 является частично небезопасным. Принимая это во внимание, я хотел бы знать, какой механизм использовать для защиты паролем.

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

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

  • Механизм хэширования должен быть доступен в PHP
  • Это должно быть безопасно
  • Он может использовать соль (в этом случае, все соли одинаково хороши? Есть ли способ создать хорошие соли?)

Кроме того, следует ли хранить два поля в базе данных (например, с использованием MD5 и другого с использованием SHA)? Будет ли это сделать его более безопасным или бессовестным?

Если я не был достаточно ясен, я хочу знать, какие функции хеширования использовать и как выбрать хорошую соль, чтобы иметь безопасный и быстрый механизм защиты паролем.

Связанные вопросы, которые не совсем охватывают мой вопрос:

Какая разница между SHA и MD5 в PHP
Простой шифрование пароля
Защищенные методы хранения ключей, паролей для asp.net
Как бы вы реализовали соленые пароли в Tomcat 5.5

Ответы

Ответ 1

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ. Этот ответ был написан в 2008 году.

С тех пор PHP дал нам password_hash и password_verify, и с момента их введения они рекомендуются для хэширования и проверки пароля.

Теория ответа по-прежнему хорошо читается.

TL; DR

Этикет

  • Не ограничивайте, какие символы пользователи могут вводить для паролей. Только идиоты делают это.
  • Не ограничивайте длину пароля. Если вашим пользователям требуется предложение с supercalifragilisticexpialidocious в нем, не мешайте им использовать его.
  • Никогда не храните свой пароль пользователя в текстовом формате.
  • Никогда не отправляйте по электронной почте пароль своему пользователю, за исключением случаев, когда они потеряли их, и вы отправили временный пароль.
  • Никогда, никогда не регистрируйте пароли каким-либо образом.
  • Никогда не используйте хеш-пароли с SHA1 или MD5 или даже SHA256! Современные крекеры могут превышать 60 и 180 миллиардов хэшей в секунду (соответственно).
  • Не смешивайте bcrypt и с исходным результатом hash(), либо используйте hex output, либо base64_encode. (Это относится к любому входу, который может содержать в нем жулик \0, что может серьезно ослабить безопасность.)

Dos

  • Используйте scrypt, когда можете; bcrypt, если вы не можете.
  • Используйте PBKDF2, если вы не можете использовать bcrypt или scrypt, с хэшами SHA2.
  • Reset все пароли, когда база данных скомпрометирована.
  • Внедрите разумную минимальную длину 8-10 символов, плюс потребуйте хотя бы 1 букву в верхнем регистре, 1 строчную букву, номер и символ. Это улучшит энтропию пароля, в свою очередь, усложнит процесс взлома. (См. Раздел "Что делает хороший пароль?" Для обсуждения).

Почему хеш-пароли в любом случае?

Цель зашифрованных паролей проста: предотвращение вредоносного доступа к учетным записям пользователей путем компрометации базы данных. Таким образом, цель хэширования пароля состоит в том, чтобы сдержать хакера или взломщика, потратив слишком много времени или денег на вычисление паролей с открытым текстом. И время/стоимость - лучшие сдерживающие факторы в вашем арсенале.

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

Джереми Гроссман, технический директор Whitehat Security, заявил в своем блоге после недавнего восстановления пароля, требующего грубой защиты от его защиты паролем:

Интересно, что, выйдя из этого кошмара, я узнал, что LOT я не знал о взломе, хранении и сложности паролей. Я понимаю, почему хранение паролей становится гораздо более важным, чем сложность паролей. Если вы не знаете, как хранится ваш пароль, то все, от чего вы действительно можете зависеть, - это сложность. Это может быть общим знанием для паролей и криптоваторов, но для среднего специалиста InfoSec или Web Security я очень сомневаюсь в этом.

(Подчеркните мой.)

Что делает хороший пароль в любом случае?

Энтропия. (Не то, чтобы я полностью подписался на точку зрения Рэндалла.)

Короче говоря, энтропия - это то, насколько вариация находится в пароле. Когда пароль является только строчными римскими буквами, это всего 26 символов. Это не так много. Альфа-числовые пароли лучше, с 36 символами. Но разрешение верхнего и нижнего регистра с символами составляет примерно 96 символов. Это намного лучше, чем просто письма. Одна из проблем заключается в том, чтобы сделать наши пароли незабываемыми, мы вставляем шаблоны, что уменьшает энтропию. К сожалению,

Энтропия пароля приближена легко. Использование полного диапазона символов ascii (примерно 96 символов типа) дает энтропию 6,6 на символ, которая с 8 символами для пароля все еще слишком низка (52,679 бит энтропии) для будущей безопасности. Но хорошей новостью является: более длинные пароли и пароли с символами юникода, действительно увеличивают энтропию пароля и затрудняют его взломы.

Там больше обсуждается энтропия паролей на сайте Crypto StackExchange. Хороший поиск Google также принесет много результатов.

В комментариях я поговорил с @popnoodles, который указал, что применение политики паролей длины X с X многими буквами, цифрами, символами и т.д. может фактически уменьшить энтропию, сделав схему паролей более предсказуемой. Я согласен. Случайность, по возможности случайная, всегда является самым безопасным, но наименее запоминающимся решением.

Насколько я мог сказать, сделать лучший в мире пароль - это Catch-22. Либо не слишком запоминающийся, слишком предсказуемый, слишком короткий, слишком много символов Юникода (трудно набирать на устройстве Windows/Mobile) слишком долго и т.д. Никакой пароль действительно не достаточно хорош для наших целей, поэтому мы должны защищать их, как если бы они были в Форт-Ноксе.

Рекомендации

Bcrypt и scrypt - текущие лучшие практики. scrypt будет лучше, чем bcrypt во времени, но он не видел принятия в качестве стандарта Linux/Unix или веб-серверами и hasn У него были подробные обзоры его алгоритма. Но, тем не менее, будущее алгоритма выглядит многообещающим. Если вы работаете с Ruby, есть scrypt gem, который поможет вам, а Node.js теперь имеет свой собственный scrypt. Вы можете использовать Scrypt в PHP либо через расширение Scrypt, либо Libsodium (оба доступны в PECL).

Я настоятельно рекомендую прочитать документацию для функции crypt, если вы хотите понять, как использовать bcrypt, или найти себя хороший обертка или используйте что-то вроде PHPASS для более старой реализации. Я рекомендую минимум 12 раундов bcrypt, если не 15-18.

Я передумал использовать bcrypt, когда узнал, что bcrypt использует только расписание ключевых слов blowfish с механизмом переменных затрат. Последний позволяет вам увеличить стоимость перебора пароля, увеличив при этом уже дорогостоящий ключевой график blowfish.

Средние практики

Я почти не могу представить эту ситуацию. PHPASS поддерживает PHP 3.0.18 - 5.3, поэтому его можно использовать практически во всех установках, которые можно вообразить, и их следует использовать, если вы не знаете что ваша среда поддерживает bcrypt.

Но предположим, что вы вообще не можете использовать bcrypt или PHPASS. Что тогда?

Попробуйте выполнить PDKBF2 с максимальным количеством раундов в вашей среде/приложение/восприятие пользователя могут терпеть. Самое низкое число, которое я бы рекомендовал, - 2500 раундов. Кроме того, убедитесь, что hash_hmac(), если он доступен, чтобы сделать операцию сложнее воспроизвести.

Будущие практики

В PHP 5.5 есть полная библиотека защиты паролей которая абстрагирует все усилия по работе с bcrypt. Хотя большинство из нас застряли в PHP 5.2 и 5.3 в большинстве распространенных сред, особенно на общих хостах, @ircmaxell построил уровень совместимости для будущего API которая обратно совместима с PHP 5.3.7.

Репликация и отказ от криптографии

Вычислительная мощность, необходимая для взлома хэшированного пароля, не существует. Единственный способ для компьютеров "взломать" пароль - воссоздать его и имитировать алгоритм хеширования, используемый для его защиты. Скорость хэша линейно связана с его способностью к грубому принуждению. Хуже того, большинство алгоритмов хэширования можно легко распараллелить, чтобы выполнять еще быстрее. Вот почему такие дорогостоящие схемы, как bcrypt и scrypt, настолько важны.

Вы не можете предвидеть все угрозы или возможности атаки, поэтому приложите все усилия, чтобы защитить своих пользователей впереди. Если вы этого не сделаете, вы можете даже пропустить тот факт, что на вас напали, пока он не слишком поздно... и вы несете ответственность. Чтобы избежать этой ситуации, сначала начните действовать параноидально. Атакуйте свое собственное программное обеспечение (внутренне) и пытайтесь украсть учетные данные пользователя или изменять другие учетные записи пользователей или получать доступ к их данным. Если вы не проверяете безопасность своей системы, вы не можете обвинять никого, кроме себя.

Наконец: я не криптограф. Что бы я ни сказал, это мое мнение, но я считаю, что это основано на здравом смысле... и на большом количестве чтения. Помните, как можно более параноично, как можно более трудно вмешаться, а затем, если вы все еще беспокоитесь, обратитесь к хакерам или криптографу из белых хатов, чтобы узнать, что они говорят о вашем коде/системе.

Ответ 2

Гораздо более короткий и безопасный ответ - вообще не пишите свой собственный механизм паролей, используйте проверенный и проверенный механизм.

  • PHP 5.5 или выше: password_hash() - это хорошее качество и часть ядра PHP.
  • Старые версии PHP: библиотека php OpenWall намного лучше, чем большинство пользовательских кодов - используется в WordPress, Drupal и т.д.

Большинство программистов просто не имеют опыта безопасного написания кода, связанного с криптографией, без внедрения уязвимостей.

Быстрый самотестирование: что такое растяжка пароля и сколько итераций вы должны использовать? Если вы не знаете ответа, вы должны использовать password_hash(), поскольку растяжение пароля теперь является важной особенностью механизмов паролей из-за гораздо более быстрых процессоров и использования графических процессоров и FPGA для взлома паролей со скоростью в несколько миллиардов догадок в секунду (с графическими процессорами).

Например, вы можете взломать все 8-символьные пароли Windows за 6 часов, используя 25 графических процессоров, установленных на 5 настольных ПК. Это грубое принуждение, то есть перечисление и проверка каждого 8-символьного пароля Windows, включая специальные символы, и не является атакой по словарю. Это было в 2012 году, по состоянию на 2018 год вы могли бы использовать меньше графических процессоров или быстрее раскодировать с 25 графическими процессорами.

Также есть много радужных табличных атак на пароли Windows, которые работают на обычных процессорах и очень быстрые. Все это связано с тем, что Windows по-прежнему не поддерживает и не расширяет свои пароли, даже в Windows 10, - не делайте ту же ошибку, что и Microsoft!

Смотрите также:

Ответ 3

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

Ответ 4

Начиная с PHP 5.5, PHP имеет простые, безопасные функции для хэширования и проверки паролей, password_hash() и password_verify()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

Когда используется password_hash(), он генерирует случайную соль и включает ее в выведенный хэш (наряду с затратами и используемым алгоритмом). password_verify() затем считывает этот хэш и определяет используемый метод соли и шифрования и проверяет его на предоставленный пароль открытого текста.

Предоставление PASSWORD_DEFAULT инструктирует PHP использовать алгоритм хэширования по умолчанию для установленной версии PHP. Именно тот алгоритм, который означает, со временем изменяется в будущих версиях, так что он всегда будет одним из самых сильных доступных алгоритмов.

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

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

Ответ 5

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

Дополнительное объяснение доступно в http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

Недавно у меня возникла дискуссия о том, было ли хэш-пароль, соленый со случайными биты более безопасны, чем та, что соленая с догадкими или известными соли. Давайте посмотрим: если система, хранящая пароль, скомпрометирована как а также система, в которой хранится случайная соль, злоумышленник будет имеют доступ к хешу, а также к соли, поэтому, является ли соль случайной или не, не имеет значения. Злоумышленник может генерировать предварительно вычисленные радужные столы, чтобы взломать хэш. Вот интересная часть не так тривиально, чтобы генерировать предварительно вычисленные таблицы. Возьмем пример модели безопасности WPA. Ваш пароль WPA на самом деле никогда не отправляется Беспроводная точка доступа. Вместо этого он хэшируется с вашим SSID ( имя сети, как Linksys, Dlink и т.д.). Очень хорошее объяснение того, как это работает здесь. Чтобы получить пароль из хэша, вы необходимо знать пароль, а также соль (имя сети). Церковь Wifi уже предварительно вычисленных хэш-таблиц, которые имеют 1000 идентификаторов SSID и около 1 миллиона паролей. Размер всех таблиц составляет около 40 ГБ. Как вы можете прочитать на своем сайте, кто-то использовал 15 массивов FGPA в течение 3 дней для создания этих таблиц. Предполагая, что жертва использует SSID как "a387csf3" и пароль как "123456", будут ли они таблицы? Нет!.. это не может. Даже если пароль слабый, таблицы не имеет хешей для SSID a387csf3. Это красота того, что случайная соль. Это будет сдерживать крекеры, которые преуспевают на заранее вычисленных столы. Может ли он остановить определенного хакера? Возможно нет. Но используя случайные соли обеспечивают дополнительный уровень защиты. Пока мы на эта тема, давайте обсудим дополнительное преимущество хранения случайных соли на отдельной системе. Сценарий № 1: Хэши паролей хранятся по системе X и значениям соли, используемым для хеширования, хранятся в системе Y. Эти значения соли являются допустимыми или известными (например, имя пользователя). Сценарий № 2: Хэши паролей хранятся в системе X и значения соли, используемые для хеширование хранятся в системе Y. Эти значения соли являются случайными. В случае система X была скомпрометирована, как вы можете догадаться, есть огромный преимущество использования случайной соли в отдельной системе (сценарий № 2). Злоумышленнику нужно угадать дополнительные значения, чтобы иметь возможность взломать хэши. Если используется 32-битная соль, 2 ^ 32 = 4 294 967 296 (около 4,2 миллиард) могут потребоваться итерации для каждого предполагаемого пароля.

Ответ 6

Я просто хочу отметить, что PHP 5.5 включает API хеширования паролей, который предоставляет оболочку вокруг crypt(). Этот API значительно упрощает задачу хэширования, проверки и повторного использования хэшей паролей. Автор также выпустил пакет совместимости (в виде одного файла password.php, который вы просто используете require), для тех, кто использует PHP 5.3.7 и позже, и хотите использовать это прямо сейчас.

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

API предоставляет четыре функции:

  • password_get_info() - возвращает информацию о данном хеше
  • password_hash() - создает хеш пароля
  • password_needs_rehash() - проверяет, соответствует ли данный хэш заданным параметрам. Полезно проверить, соответствует ли хэш вашей текущей схеме техники/стоимости, позволяя вам перефразировать при необходимости
  • password_verify() - проверяет, соответствует ли пароль хешу

В настоящее время эти функции принимают константы паролей PASSWORD_BCRYPT и PASSWORD_DEFAULT, которые в настоящий момент являются синонимами, разница в том, что PASSWORD_DEFAULT "может измениться в новых версиях PHP, когда поддерживаются более новые и более сильные алгоритмы хеширования". Использование PASSWORD_DEFAULT и password_needs_rehash() при входе в систему (и повторная перестановка в случае необходимости) должно гарантировать, что ваши хэши достаточно устойчивы к атакам с использованием грубой силы, для вас практически не работает.

EDIT: Я просто понял, что это кратко сказано в ответе Роберта К. Я оставлю этот ответ здесь, так как я думаю, что он предоставляет немного больше информации о том, как он работает, и простота использования, предоставляемая тем, кто не знает безопасности.

Ответ 7

Я использую Phpass, который является простым однофайльным PHP-классом, который может быть реализован очень легко почти в каждом проекте PHP. См. Также H.

По умолчанию он использовал самое сильное доступное шифрование, которое реализовано в Phpass, которое bcrypt и возвращается к другим шифрованиям вплоть до MD5, чтобы обеспечить обратную совместимость с такими фреймворками, как Wordpress.

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

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

Чтобы проверить пароль, можно использовать:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

Ответ 8

ВЕЩИ ПОМНИТЬ

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

SERVER

ПОРТЫ

Независимо от того, насколько хорошо ваше шифрование, если вы не должным образом защищаете сервер, на котором запущены PHP и DB, все ваши усилия бесполезны. Большинство серверов функционируют относительно одинаково, у них есть порты, назначенные для удаленного доступа к ним через ftp или shell. Убедитесь, что вы изменили порт по умолчанию, с которым вы когда-либо делали удаленное соединение. Не делая этого, вы фактически сделали злоумышленника сделать еще один шаг в доступе к вашей системе.

ИМЯ_ПОЛЬЗОВАТЕЛЯ

Для всего, что хорошо в мире, не используйте имя пользователя admin, root или что-то подобное. Кроме того, если вы используете систему на основе unix, НЕ делайте вход в учетную запись root доступной, она всегда должна быть только sudo.

ПАРОЛЬ

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

DATABASE

СЕРВЕР

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

USER

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

Затем у вас есть отдельная учетная запись пользователя, которая не хранится нигде на сервере, даже в приложении.

Как всегда НЕ делайте этот корень или что-то подобное.

ПАРОЛЬ

Следуйте тем же рекомендациям, что и со всеми хорошими паролями. Также не используйте повторно один и тот же пароль для любых учетных записей SERVER или DB в той же системе.

PHP

ПАРОЛЬ

НИКОГДА НЕ сохраняйте пароль в своей БД, вместо этого храните хеш и уникальную соль, я объясню, почему позже.

хэширования

ONE WAY HASHING!!!!!!!, никогда не хешируйте пароль таким образом, чтобы его можно было отменить, хэш должен быть одним из способов, то есть вы не отменяете их и не сравниваете с паролем, вы вместо этого хеш введенный пароль таким же образом и сравнить два хэша. Это означает, что даже если злоумышленник получает доступ к БД, он не знает, что такое собственно пароль, а просто его хэш. Это означает большую безопасность для ваших пользователей в худшем возможном сценарии.

Существует множество хороших хэширующих функций (password_hash, hash и т.д.), но вам нужно выбрать хороший алгоритм для хеша, который будет эффективным. (bcrypt и аналогичные ему алгоритмы являются достойными алгоритмами.)

Когда скорость хеширования является ключом, тем медленнее становится более устойчивым к атакам Brute Force.

Одна из самых распространенных ошибок хэширования заключается в том, что хеши не уникальны для пользователей. Это связано главным образом с тем, что соли не генерируются однозначно.

посола

Пароли всегда должны быть солеными перед хешированием. Salting добавляет случайную строку к паролю, поэтому аналогичные пароли не отображаются одинаково в БД. Однако, если соль не уникальна для каждого пользователя (то есть: вы используете твердую кодированную соль), чем вы в значительной степени сделали вашу соль бесполезной. Потому что, как только нападающий обнаруживает одну соль паролей, у него есть соль для всех.

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

ПОЛЬЗОВАТЕЛИ, СОЗДАВАЯ ПАРОЛЬ

Если пользователь создает пароль через интерфейс, это означает, что он должен быть отправлен на сервер. Это открывает проблему безопасности, поскольку это означает, что незашифрованный пароль отправляется на сервер, и если злоумышленник может слушать и получать доступ к тому, что вся ваша безопасность в PHP бесполезна. ВСЕГДА передавайте данные БЕЗОПАСНО, это делается через SSL, но утомляйтесь, даже SSL не безупречен (примером этого является OpenSSL Heartbleed.

Также создайте для пользователя безопасный пароль, он прост и всегда должен быть выполнен, пользователь будет благодарен за это в конце.

Наконец, независимо от того, какие меры безопасности вы ничего не берете, это на 100% безопаснее, чем более продвинутая технология защиты становится более продвинутой, тем больше становятся атаки. Но следующие шаги сделают ваш сайт более безопасным и гораздо менее желательным для злоумышленников.

Вот класс PHP, который легко создает хэш и соль для пароля.

http://git.io/mSJqpw

Ответ 9

Google говорит, что SHA256 доступен для PHP.

Вы должны обязательно использовать соль. Я бы рекомендовал использовать случайные байты (и не ограничивать себя символами и цифрами). Как обычно, чем дольше вы выбираете, тем безопаснее и медленнее. 64 байта должно быть хорошо, я думаю.

Ответ 10

Я нашел прекрасную тему по этому вопросу здесь: https://crackstation.net/hashing-security.htm, я хотел, чтобы вы получили от этого выгоду, здесь также есть исходный код Кроме того, предотвращалась также атака, основанная на времени.

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

Ответ 11

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

Ответ 12

Я обычно использую SHA1 и соль с идентификатором пользователя (или некоторым другим пользовательским фрагментом информации), а иногда я пользуюсь постоянной солью (поэтому у меня есть 2 части соли).

SHA1 теперь также считается несколько скомпрометированным, но в гораздо меньшей степени, чем MD5. Используя соль (любую соль), вы предотвращаете использование родового радужного стола для атаки ваших хэшей (некоторые люди даже добились успеха используя Google как своего рода радужный стол, ища хэш). Злоумышленник может генерировать радужный стол, используя вашу соль, поэтому вы должны включить соль для конкретного пользователя. Таким образом, им придется создавать радужный стол для каждой записи в вашей системе, а не только для всей вашей системы! При таком типе соления даже MD5 прилично защищает.

Ответ 13

SHA1, и соль должна быть достаточной (в зависимости, естественно, от того, кодируете ли вы что-то для Fort Knox или система входа в систему для вашего списка покупок) в обозримом будущем. Если SHA1 недостаточно для вас, используйте SHA256.

Идея соли заключается в том, чтобы выбросить результаты хэширования из равновесия, так сказать. Известно, например, что MD5-хэш пустой строки d41d8cd98f00b204e9800998ecf8427e. Итак, если кто-то с достаточно хорошей памятью увидит этот хэш и узнает, что это хэш пустой строки. Но если строка соленая (скажем, со строкой "MY_PERSONAL_SALT" ), хеш для "пустой строки" (т.е. "MY_PERSONAL_SALT" ) становится aeac2612626724592271634fb14d3ea6, что, следовательно, неочевидно для backtrace. То, что я пытаюсь сказать, лучше использовать любую соль, чем не. Поэтому не слишком важно знать, какую соль использовать.

На самом деле есть веб-сайты, которые делают именно это - вы можете прокормить его хэшем (md5), и он выплескивает известный открытый текст, который генерирует этот конкретный хеш. Если вы получите доступ к базе данных, в которой хранятся простые md5-хеши, вам было бы тривиально вводить хэш для администратора в такую ​​службу и входить в систему. Но если пароли были солеными, такая услуга станет неэффективен.

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

Ответ 14

ОК в fitsy нам нужна соль соль должна быть уникальной поэтому пусть сгенерирует его

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

также нужен хеш Я использую sha512 он лучший, и он находится в php

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

теперь мы можем использовать эти функции для создания безопасного пароля

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

теперь нам нужно сохранить в базе данных значение переменной $hash_psw и переменную $salt

и для авторизации мы будем использовать те же шаги...

это лучший способ защитить пароли наших клиентов...

P.s. за последние 2 шага вы можете использовать свой собственный алгоритм... но будьте уверены, что вы можете генерировать этот хешированный пароль в будущем когда вам нужно авторизовать пользователя...