Солить мои хэши с PHP и MySQL

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

Я нахожу все эти классные способы шифрования паролей (SHA-256, но MySQL поддерживает только SHA/1 и MD5?) и другие вещи из руководства PHP, но не уверен, как хранить и извлекать пароли.

Итак, это все, что я понимаю:

SHA('$salt'.'$password') // My query sends the password and salt 
                         // (Should the $salt be a hash itself?)

После этого я теряюсь с солями.

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

EDIT: Является ли ключевая переменная в HMAC, которая должна быть солью, или это что-то еще?

Ответ 1

Прежде всего, ваша СУБД (MySQL) не нуждается в поддержке криптографических хэшей. Вы можете сделать все это на стороне PHP, и это также то, что вы должны делать.

Если вы хотите сохранить соль и хэш в том же столбце, вам нужно их конкатенировать.

// the plaintext password
$password = (string) $_GET['password'];

// you'll want better RNG in reality
// make sure number is 4 chars long
$salt = str_pad((string) rand(1, 1000), 4, '0', STR_PAD_LEFT);

// you may want to use more measures here too
// concatenate hash with salt
$user_password = sha512($password . $salt) . $salt;

Теперь, если вы хотите подтвердить пароль, который вы делаете:

// the plaintext password
$password = (string) $_GET['password'];

// the hash from the db
$user_password = $row['user_password'];

// extract the salt
// just cut off the last 4 chars
$salt = substr($user_password, -4);
$hash = substr($user_password, 0, -4);

// verify
if (sha512($password . $salt) == $hash) {
  echo 'match';
}

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

Вы должны обязательно взглянуть на ответ на вопрос, связанный с WolfOdrade.

Ответ 3

Лично я рекомендую разрешить MySQL делать это с помощью встроенных функций.

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

function enc_key(){
     return "aXfDs0DgssATa023GSEpxV";
}

Затем в вашем script используйте его с запросом sql и функциями AES_ENCRYPT и AES_DECRYPT в MySQL следующим образом:

require_once('dbconf.inc.php');

$key = enc_key();

//When creating a new user
$sql = "INSERT INTO users (username, password) VALUES ('bob', AES_ENCRYPT('{$key}', {$password}))";

//When retrieving users password
$sql = "SELECT AES_DECRYPT('{$key}', password) AS password FROM users WHERE username like 'bob'";