Как я могу сохранить хэш с солеными паролями, если у меня только один столбец базы данных? - PullRequest
1 голос
/ 12 мая 2010

Я прочитал несколько ТАКИХ вопросов по этой теме, но мне не хватает практической практики хранения соленого хэша пароля.

Давайте начнем с некоторых основных правил:

  • пароль, "foobar12" (мы не обсуждаем надежность пароля).
  • язык, Java 1.6 для этого обсуждения
  • база данных, postgreSQL, MySQL, SQL Server, Oracle

Для хранения пароля доступно несколько вариантов, но я хочу подумать об одном (1):

Хранить хэшированный пароль со случайной солью в БД, один столбец

Автоматический сбой хранения открытого текста не открыт для обсуждения. :) На SO и в других местах найдены решения с MD5 / SHA1 и использованием двойных колонок, как с плюсами, так и с минусами.

MD5 / SHA1 прост. MessageDigest в Java предоставляет MD5, SHA1 (через SHA512 в современных реализациях, конечно, 1.6). Кроме того, большинство перечисленных СУБД предоставляют методы для функций шифрования MD5 при вставках, обновлениях и т. Д. Проблемы становятся очевидными после того, как кто-то получает "радужные таблицы" и коллизии MD5 (и я ухватился за эти понятия).

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

Но это хранение хэша пароля со случайной солью в одном столбце БД , что мне нужно лучше понять, с практическим применением.

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

У меня есть теория на этот счет, и, когда я набираю текст, я, возможно, уклоняюсь от концепции: учитывая случайную соль из 128 байтов и пароль из 8 байтов ('foobar12'), программно можно было бы удалить часть хеш, который был солью, путем хеширования случайной 128-байтовой соли и получения подстроки исходного хеша, который является хешированным паролем. Затем повторное хеширование для соответствия с использованием алгоритма хеширования ...?

Так что ... все желающие помогают. :) Я близко?

Ответы [ 5 ]

4 голосов
/ 12 мая 2010

Нет большой загадки. Решение с одним столбцом похоже на решение с несколькими столбцами, за исключением того, что оно объединяет соль и хеш вместе в один столбец. Проверочный код все еще должен знать, как разбить это единственное значение на соль и хеш. (Именно так обычно работали соленые пароли - например, формат UNIX /etc/shadow хранит идентификатор алгоритма, соль и хеш вместе в одном поле).

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

  • Сохранить строку, возвращаемую BCrypt.hashpw() в столбце пароля базы данных при сохранении пароля; и
  • Введите значение из столбца пароля базы данных в качестве второго параметра для BCrypt.checkpw() при проверке пароля.
1 голос
/ 12 мая 2010

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

Если у вас есть только один столбец для хранения пароля, вы можете:

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

В первом случае вы можете придумать некоторую тривиальную функцию:

public String getSalt(String username)
{
  // assuming Hash returns a String
  return Hash(username + " 1234 my site is totally awesome").substring(0,16);
}

Во втором:

// Passwords stored in the db as 16 characters of salt, and the rest is password hash
public boolean authenticate(String username, String authPassword)
{
  // 'SELECT saltyhash FROM users WHERE username=x'
  String saltyhash = getSaltyHashForUserFromDB(username);
  String salt = saltyhash.substring(0,16);

  String dbPassword = salt + Hash(salt + authPassword);

  // perform the actual 'SELECT FROM users WHERE saltypassword=x' stuff
  return hitTheDatabaseToPerformLogin(username, dbPassword);
}

public void createUser(String username, String password)
{
  String salt = createSomeAwesomeSalt();
  String saltyhash = salt + Hash(salt + password);
  createTheUserInTheDatabase(username, saltyhash);
}
1 голос
/ 12 мая 2010

Вы также можете хранить соль и хеш в одном столбце (используя разделитель).

0 голосов
/ 12 мая 2010

Вот где я теряюсь: если соль является случайным и перемешивается с пароль, как система может когда-либо сопоставить пароль?

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

0 голосов
/ 12 мая 2010

См. http://www.aspheute.com/english/20040105.asp

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

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

Соленый хеш создается следующим образом:

  // Initialize the Password class with the password and salt
  Password pwd = new Password(myPassword, mySalt);

  // Compute the salted hash
  // NOTE: you store the salt and the salted hash in the database
  string saltedHash = pwd.ComputeSaltedHash();

Аутентификация выполняется следующим образом:

// retrieve salted hash and salt from user database, based on username
...

Password pwd = new Password(txtPassword.Text, nSaltFromDatabase);

if (pwd.ComputeSaltedHash() == storedSaltedHash)
{
   // user is authenticated successfully
}
else
{
...

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

...