Хеш-функция всегда возвращает одно и то же значение для одной и той же входной строки. Допустим, мой пользователь (Алиса) имеет пароль secret
. Хеширование secret
с использованием md5()
приводит к следующему хешу
5ebe2294ecd0e0f08eab7690d2a6ee69
Используя словарь (список общих слов и пароль) или один из различных сайтов, предлагающих вам эту услугу, злоумышленник (Мэллори) может легко узнать, что пароль является секретным, когда он видит в своем словаре, что 5ebe2294ecd0e0f08eab7690d2a6ee69 = secret
.
Процесс посола перед хэшированием затрудняет использование атаки по словарю, не зная вашей соли. Учтите следующее:
<?php
$salt = '@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!';
$hash = md5($salt . 'secret');
Полученный хеш теперь равен b58ad809eece17322de5024d79299f8a
, но пароль Алисы по-прежнему secret
. Теперь, если Мэллори достанет соленый хеш, скорее всего, она не найдет ответ в своем словаре. Если она это сделает, словарь даст ей неправильный ответ.
Никогда не храните статическую соль в вашей базе данных. Желательно хранить его с конфигурацией вашего приложения (которая, кстати, не должна быть доступна в Интернете).
Если вы собираетесь использовать динамическую соль, вам нужно будет использовать базу данных. Используйте ненулевой столбец существующих действительных данных для построения вашей соли (зашифрованная строка имени пользователя, основанная на секретном ключе шифрования, обычно криптографически безопасна). Не используйте отдельный столбец для соли. Если вы не можете использовать существующий столбец, включите вашу соль в тот же столбец, что и ваш хэш. Например, используйте первые 32 символа для вашей 128-битной соли, а затем последние 40 для 160-битного хеша. Следующая функция сгенерирует такой хеш:
function seeded_sha1($string, $seed_bits) {
if(($seed_bits % 8) != 0) {
throw new Exception('bits must be divisible by 8');
}
$salt = '';
for($i = 0; $i < $seed_bits; $i+=8) {
$salt .= pack('c', mt_rand());
}
$hexsalt = unpack('h*hex', $salt);
return $hexsalt['hex'] . sha1($salt . $string);
}
function compare_seeded_sha1($plain, $hash) {
$sha1 = substr($hash, -40);
$salt = pack('h*', substr($hash, 0, -40));
$plain_hash = sha1($salt . $plain);
return ($plain_hash == $sha1);
}
Если злоумышленник войдет в вашу базу данных с помощью SQL-инъекции, то по крайней мере хеш-коды, которые он / она получит, будут бесполезны, поскольку у него / нее не будет доступа к конфигурации вашего приложения. Если ваш сервер рутирован, он в значительной степени закончен, независимо от того, что вы делаете.
Примечание: Возможны другие типы атак на md5()
, поэтому вы используете более безопасный алгоритм хеширования, например, sha1()
. Или, что еще лучше, используйте Portable PHP хэширование паролей , разработанное с учетом требований безопасности и обратно совместимое практически с любой версией 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 $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}