PHP
Функции хеширования пароля
Поиск…
Вступление
Поскольку более безопасные веб-службы не позволяют хранить пароли в текстовом формате, языки, такие как PHP, предоставляют различные (неразрешимые) хэш-функции для поддержки более безопасного отраслевого стандарта. В этом разделе представлена документация для правильного хеширования с помощью PHP.
Синтаксис
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
замечания
До PHP 5.5 вы можете использовать пакет совместимости для предоставления функций password_*
. Настоятельно рекомендуется использовать пакет совместимости, если вы в состоянии это сделать.
С пакетом совместимости или без него правильная функция Bcrypt через crypt()
зависит от PHP 5.3.7+, иначе вы должны ограничить пароли только наборами символов ASCII.
Примечание. Если вы используете PHP 5.5 или ниже, вы используете неподдерживаемую версию PHP, которая больше не получает никаких обновлений безопасности. Обновление как можно скорее, вы можете обновить хэши паролей.
Выбор алгоритма
Защищенные алгоритмы
- bcrypt - ваш лучший вариант, пока вы используете растяжение клавиш, чтобы увеличить время вычисления хеша, поскольку оно делает атаки грубой силы чрезвычайно медленными .
- Аргон2 - еще один вариант, который будет доступен в PHP 7.2 .
Небезопасные алгоритмы
Следующие алгоритмы хеширования являются небезопасными или непригодными для использования и поэтому не должны использоваться . Они никогда не были пригодны для хэширования паролей, поскольку они предназначены для быстрых дайджестов, а не для медленных и сложных для перебора пароля.
Если вы используете какой-либо из них , включая соли, вы должны как можно скорее переключиться на один из рекомендуемых безопасных алгоритмов.
Алгоритмы считаются небезопасными:
- MD4 - атака столкновения, обнаруженная в 1995 году
- MD5 - атака столкновения, обнаруженная в 2005 году
- SHA-1 - атака столкновения, продемонстрированная в 2015 году
Некоторые алгоритмы могут быть безопасно использованы в качестве алгоритма дайджеста сообщений для подтверждения подлинности, но никогда не как алгоритм хэширования паролей :
- SHA-2
- SHA-3
Заметьте, что сильные хэши, такие как SHA256 и SHA512, являются непрерывными и надежными, однако, как правило, более безопасно использовать функции bcrypt или argon2 хеш-функции, поскольку атаки с применением перебора для этих алгоритмов гораздо сложнее для классических компьютеров.
Определите, может ли существующий хеш пароля обновиться до более сильного алгоритма
Если вы используете метод PASSWORD_DEFAULT
чтобы система выбрала лучший алгоритм для хэширования ваших паролей, по мере того, как по умолчанию усиливается сила, вы можете переустановить старые пароли при входе пользователей в систему
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Если функции password_ * недоступны в вашей системе (и вы не можете использовать пакет совместимости, связанный в примечаниях ниже), вы можете определить алгоритм и использовать для создания исходного хэша в методе, подобном следующему:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Создание хэша паролей
Создавайте хэши паролей, используя password_hash()
чтобы использовать текущую стандартную хэш-версию или ключевой вывод. На момент написания статьи стандартом является bcrypt , что означает, что PASSWORD_DEFAULT
содержит то же значение, что и PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
Третий параметр не является обязательным .
Значение 'cost'
должно быть выбрано на основе аппаратного обеспечения вашего производственного сервера. Увеличение его сделает пароль более дорогостоящим для генерации. Чем дороже, тем больше времени потребуется, чтобы кто-то попытался взломать его, чтобы сгенерировать его. Стоимость в идеале должна быть как можно выше, но на практике она должна быть установлена так, чтобы она не замедляла слишком много. Где-то между 0,1 и 0,4 секунды было бы хорошо. Используйте значение по умолчанию, если у вас есть сомнения.
На PHP ниже 5.5.0 функции password_*
недоступны. Вы должны использовать пакет совместимости для замены этих функций. Обратите внимание, что для пакета совместимости требуется PHP 5.3.7 или более поздняя версия или версия, в которую $2y
резервное $2y
(например, RedHat).
Если вы не можете их использовать, вы можете реализовать хеширование паролей с помощью crypt()
Поскольку password_hash()
реализуется как оболочка вокруг функции crypt()
, вам не нужно терять функциональность.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Соль для хеша пароля
Несмотря на надежность алгоритма криптографии, по-прежнему существует уязвимость против радужных таблиц . Вот почему, поэтому рекомендуется использовать соль .
Соль - это то, что добавлено к паролю перед хэшированием, чтобы сделать исходную строку уникальной. Учитывая два идентичных пароля, полученные хеши будут также уникальными, поскольку их соли уникальны.
Случайная соль - одна из важнейших частей вашей защиты паролем. Это означает, что даже с помощью таблицы поиска известных хэшей пароля злоумышленник не может сопоставить хэш пароля вашего пользователя с хэшами паролей базы данных, так как используется случайная соль. Вы должны использовать всегда случайные и криптографически безопасные соли. Прочитайте больше
С помощью алгоритма bcrypt
password_hash()
сохраняется соль обычного текста вместе с полученным хешем, что означает, что хэш может быть передан через разные системы и платформы и по-прежнему сопоставляться с исходным паролем.
Даже если это не рекомендуется, вы можете использовать опцию salt
чтобы определить вашу собственную случайную соль.
$options = [
'salt' => $salt, //see example below
];
Важно . Если вы опустите эту опцию, случайная соль будет сгенерирована с помощью пароля_hash () для каждого хэша. Это назначенный режим работы.
Опция salt устарела с PHP 7.0.0. В настоящее время предпочтительнее просто использовать соль, которая генерируется по умолчанию.
Проверка пароля на хэш
password_verify()
- это встроенная функция (начиная с PHP 5.5), чтобы проверить правильность пароля для известного хэша.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Все поддерживаемые алгоритмы хэширования сохраняют информацию, идентифицирующую, какой хэш использовался в самом хеше, поэтому нет необходимости указывать, какой алгоритм вы используете для кодирования пароля с открытым текстом.
Если функции password_ * недоступны в вашей системе (и вы не можете использовать пакет совместимости, связанный в примечаниях ниже), вы можете реализовать проверку пароля с помощью функции crypt()
. Обратите внимание, что необходимо избегать временных атак .
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>