Как реализовать salt в моем логине для паролей?

Я хочу реализовать соль в моей системе входа в систему, но немного смущен тем, как это должно работать. Я не могу понять логику этого. Я понимаю, что md5-это односторонний алгоритм, и все функции, с которыми я столкнулся, похоже, хешируют все вместе. Если это так, то как получить пароль обратно для сравнения? Мой самый большой вопрос: Как солить пароль пользователя безопаснее, чем просто хэшировать пароль? Если база данных не будет нарушена, хэш вместе с солью есть в базе данных. Разве это не все, что нужно хакеру?

Я также нашел еще один пост здесь, где другой разработчик сказал:

"обеспечить солью и алгоритма хранится отдельно на базе"

Я хотел бы хранить соль в базе данных. Это действительно проблема, если я это сделаю?

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


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

8 ответов


хэш-функция всегда возвращает одно и то же значение для одной и той же входной строки. Допустим, у моего пользователя (Алисы) есть пароль secret. Хешинг secret используя md5() приводит к следующему хэшу

5ebe2294ecd0e0f08eab7690d2a6ee69

используя словарь (список общих слов и пароля) или один из различных сайтов, которые предлагают вам эту услугу, злоумышленник (Мэллори) может легко узнать, что пароль является секретным, когда он видит в своем словаре, что 5ebe2294ecd0e0f08eab7690d2a6ee69 = secret.

в процесс соления перед хэшированием затрудняет использование атаки словаря, не зная вашей соли. Рассмотрим следующее:

<?php
$salt = '@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!';
$hash = md5($salt . 'secret');

полученный хэш теперь b58ad809eece17322de5024d79299f8a но пароль Алисы все еще secret. Теперь, если Мэллори доберется до соленого гашиша, скорее всего, она не найдет ответа в своем словаре. Если она это сделает, словарь даст ей неправильный ответ.

никогда не храните статическую соль в базе данных. Желательно хранить его с конфигурация приложения (которая, кстати, не должна быть доступна из интернета).

если вы собираетесь использовать динамическую соль, вам нужно будет использовать базу данных. Используйте ненулевой столбец существующих допустимых данных для создания соли (зашифрованная blowfish строка имени пользователя на основе секретного ключа шифрования обычно криптографически безопасна). Не используйте отдельную колонку для соли. Если вы не можете использовать существующий столбец, включите соль в тот же столбец, что и ваш хэш. Например, используйте первые 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() например. Или, что еще лучше, используйте портативный PHP пароль хэширования framework, который был разработан с учетом безопасности и обратно совместим практически с любой версией 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';
}

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

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

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

Edit: мои рекомендации:

  • генерировать длинную псевдослучайную соль для каждого пользователя и хранить в DB
  • используйте хэш на основе bcrypt
  • в идеале, не реализуйте его самостоятельно, используйте существующий библиотека вместо

забудьте об использовании солей (частично по причине, которую вы упомянули), используйте bcrypt вместо:

для хорошего объяснения см.:http://codahale.com/how-to-safely-store-a-password/


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

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

в качестве примера наличия уникальной соли для каждого пользователя и сохранения ее рядом с хэшем пароля я укажу /etc / shadow на вашей типичной системе Linux.

root@linux:/root# cat /etc/shadow | grep root
root:$oL5TTZxL$RhfGUZSbFwQN6jnX5D.Ck/:12139:0:99999:7:::

здесь oL5TTZxL соль и RhfGUZSbFwQN6jnX5D.Ck/ это хэш. Простой текстовый пароль root в этом случае, и алгоритм хэша, который использует моя система, является алгоритмом пароля BSD на основе MD5. (более новые системы, чем мои, имеют лучшие алгоритмы хэша)


вы не получите пароль Для сравнения. Вы шифруете пароль при попытке входа в систему и сравниваете сохраненное значение с недавно зашифрованным значением.


как вы упомянули, алгоритмы хэширования работают только в одну сторону (или только если они достаточно сильны: - D)

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

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

например, предположим, у вас есть users таблица с этими столбцами:

id
username
password
created_at

колонки id и created_at после того как раз заполненный никогда не должен быть изменен..

Итак, когда вы хеширования пароля пользователя вы можете сделать так:

<?php
    $staticSalt = '!241@kadl;ap][';
    $userPass = 'my new pass';
    // assuming $user variable is already populated with DB data
    // we will generate new hash from columns and static salt:
    $genPass = sha1($user['id'] . $userPass . $user['created_at'] . $staticSalt);
?>

надеюсь, это поможет:) ура


хэширование паролей предназначено для сохранения этих паролей в секрете от вашего собственного администратора(администраторов).

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

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

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

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

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

некоторые другие Примечания:

a) вы можете использовать bcrypt в комбинации пароль/соль, чтобы замедлить атаку грубой силы злоумышленника. Но поскольку мы принимаем администраторов, они могут быть терпеливы.

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

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


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

например, если хакер получает доступ к вашей базе данных, а Пароли не засолены, он может искать хэши в своей базе данных хэшей (см. http://en.wikipedia.org/wiki/Rainbow_table), чтобы получить оригинальные пароли.