Как я могу безопасно хранить пароли моих пользователей?
Насколько это безопаснее, чем обычный 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]!";
}
7 ответов
Самый простой способ обезопасить вашу схему хранения паролей - использовать стандартную библиотеку.
Поскольку безопасность, как правило, намного сложнее и с более невидимыми возможностями взлома, чем может решить большинство программистов в одиночку, использование стандартной библиотеки почти всегда является самым простым и наиболее безопасным (если не единственным) доступным вариантом.
Новый 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 или новее, вы можете установить https://github.com/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';
}
Старая стандартная библиотека
Обратите внимание: вам это больше не нужно! Это только для исторических целей.
Взгляните на: Переносимая среда хэширования паролей 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)
- другие
Хорошо, что вам не нужно беспокоиться о деталях, эти детали были запрограммированы людьми с опытом и проверены многими людьми в Интернете.
Подробнее о схемах хранения паролей читайте в блоге Jeff Atwood: " Возможно, вы неправильно храните пароли"
Что бы вы ни делали, если вы идете на подход " Я сделаю это сам, спасибо ", не используйте 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), которая даст вам PHP 5.5 password_hash
в PHP 5.3.7+: https://github.com/ircmaxell/password_compat
Я хочу добавить:
- Не ограничивайте пароли пользователей длиной
Для совместимости со старыми системами часто устанавливают ограничение на максимальную длину пароля. Это плохая политика безопасности: если вы устанавливаете ограничение, устанавливайте его только для минимальной длины паролей.
- Не отправляйте пароли пользователей по электронной почте
Для восстановления забытого пароля необходимо отправить адрес, по которому пользователь может сменить пароль.
- Обновите хеши паролей пользователей
Хеш пароля может быть устаревшим (параметры алгоритма могут быть обновлены). Используя функцию password_needs_rehash()
Вы можете проверить это.
Я не против. Мистер Этвуд писал о силе MD5 по сравнению с радужными столами, и, в основном, с такой длинной солью, как ты сидишь довольно (хотя некоторые случайные знаки препинания / числа могут улучшить ее).
Вы также можете взглянуть на SHA-1, который, кажется, становится все более популярным в наши дни.
Вот система входа PHP + CouchDB.apache.org, которая не хранит пароли в виде открытого текста.
Согласно совету, который я прочитал, он должен быть полностью безопасным.
Код для входа в CMS: https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/boot.php#L56 звонки https://github.com/nicerapp/niceraeepp/blob/24ffrapps/nicerapp/blob/24ffrapps/blob/24ff9d03d04d06d06d06d05 L171
бизнес-код для конкретного приложения (-ов):https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/ajax_login.php#L87 звонки https://github.com/nicerapp/nicerapp13/nicerapp13/blogger/b04e6e6d06d06d6d06d6d6d6d06a08a8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa functions.php # L230, который, в свою очередь, вызывает: https://github.com/nicerapp/nicerapp/blob/2d479b3e22dce9e7073525481b775f1bf7389634/nicerapp/apps/nicer.app/webmail/recrypt.php#L2
и отредактировать данные конфигурации приложения веб-почты в базе данных:https://github.com/nicerapp/nicerapp/blob/main/nicerapp/apps/nicer.app/webmail/ajax_editConfig.php