Как безопасно хранить пароли пользователей?

Насколько безопаснее это, чем простой MD5 ? Я только начал изучать безопасность паролей. Я довольно новичок в PHP.

$salt = 'csdnfgksdgojnmfnb'; $password = md5($salt.$_POST['password']); $result = mysql_query("SELECT id FROM users WHERE username = '".mysql_real_escape_string($_POST['username'])."' AND password = '$password'"); if (mysql_num_rows($result) < 1) { /* Access denied */ echo "The username or password you entered is incorrect."; } else { $_SESSION['id'] = mysql_result($result, 0, 'id'); #header("Location: ./"); echo "Hello $_SESSION[id]!"; } 

Самый простой способ защитить вашу систему хранения паролей – это использовать стандартную библиотеку .

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

Новый API паролей PHP (5.5.0+)

Если вы используете PHP версии 5.5.0 или новее, вы можете использовать новый упрощенный хеширующий API паролей

Пример кода с использованием API паролей PHP:

 <?php // $hash is what you would store in your database $hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]); // $hash would be the $hash (above) stored in your database for this user $checked = password_verify($_POST['password'], $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

(Если вы все еще используете устаревшие версии 5.3.7 или новее, вы можете установить ircmaxell / password_compat для доступа к встроенным функциям)

Улучшение на соленых хешах: добавить перец

Если вам нужна дополнительная безопасность, пользователи безопасности теперь (2017) рекомендуют добавлять « перец » в (автоматически) соленые хэши паролей.

Существует простой класс, который надежно реализует этот шаблон, я рекомендую: Netsilik / PepperedPasswords ( github ).
Он поставляется с лицензией MIT, поэтому вы можете использовать его, как хотите, даже в проприетарных проектах.

Пример кода с использованием Netsilik/PepperedPasswords :

 <?php use Netsilik/Lib/PepperedPasswords; // Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper). $config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF'); $hasher = new PepperedPasswords($config['pepper']); // $hash is what you would store in your database $hash = $hasher->hash($_POST['password']); // $hash would be the $hash (above) stored in your database for this user $checked = $hasher->verify($_POST['password'], $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

Стандартная библиотека OLD

Обратите внимание: вам больше не нужно этого! Это здесь только для исторических целей.

Взгляните на: Переносимость хэширования PHP PHP : phpass и убедитесь, что вы используете алгоритм CRYPT_BLOWFISH , если это вообще возможно.

Пример кода с использованием phpass (v0.2):

 <?php require('PasswordHash.php'); $pwdHasher = new PasswordHash(8, FALSE); // $hash is what you would store in your database $hash = $pwdHasher->HashPassword( $password ); // $hash would be the $hash (above) stored in your database for this user $checked = $pwdHasher->CheckPassword($password, $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

PHPass реализован в некоторых довольно известных проектах:

  • phpBB3
  • WordPress 2.5+, а также bbPress
  • релиз Drupal 7 (модуль доступен для Drupal 5 и 6)
  • другие

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

Для получения дополнительной информации о схемах хранения паролей прочитайте сообщение в блоге Джеффа : « Вероятно, вы храните пароли неправильно»

Что бы вы ни делали, если вы идете на « Я сделаю это сам, спасибо », не используйте MD5 или SHA1 . Они являются хорошим алгоритмом хэширования, но считаются сломанными для целей безопасности .

В настоящее время использование крипты с использованием CRYPT_BLOWFISH – лучшая практика.
CRYPT_BLOWFISH в PHP – это реализация хэша Bcrypt. Bcrypt основан на блочном шифре Blowfish, используя дорогостоящую настройку ключа, чтобы замедлить алгоритм.

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

Лучшим способом для каждого пользователя будет уникальная соль.

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

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

С PHP 5.5 (то, что я описываю, доступно для более ранних версий, см. Ниже) за углом, я бы хотел предложить использовать его новое встроенное решение: password_hash() и password_verify() . Он предоставляет несколько опций для достижения необходимого уровня безопасности паролей (например, путем указания параметра «стоимость» через массив $options )

 <?php var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT)); $options = array( 'cost' => 7, // this is the number of rounds for bcrypt // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended ); var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options)); ?> 

вернется

 string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK." string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d." 

Как вы могли видеть, строка содержит соль, а также стоимость, указанную в параметрах. Он также содержит используемый алгоритм.

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

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

Проверка таких действий:

 var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K')); var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K')); var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.')); var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.')); 

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

Существует небольшая библиотека (один файл PHP), которая даст вам password_hash PHP 5.5 в PHP 5.3.7+: https://github.com/ircmaxell/password_compat

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

Вы также можете посмотреть на SHA-1, который, кажется, становится все более популярным в наши дни.

Я хочу добавить:

  • Не ограничивайте пароли пользователей по длине

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

  • Не отправлять пароли пользователей по электронной почте

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

  • Обновление хэшей паролей пользователей

Хэш пароля может быть устаревшим (параметры алгоритма могут быть обновлены). Используя функцию password_needs_rehash() вы можете проверить это.