Хеширование пароля - как обновить? - PullRequest
27 голосов
/ 18 октября 2010

Существует множество обсуждений о лучшем алгоритме, но что, если вы уже работаете?Как выполнить обновление без сброса настроек для пользователя?


РЕДАКТИРОВАТЬ / ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Хотя я изначально хотел решение "быстрое исправление" и выбрал ответ orip, я должен признать, что если безопасность в вашем приложениидостаточно важно, чтобы даже беспокоиться об этой проблеме, тогда быстрое решение - неправильный менталитет, и его предложенное решение, вероятно, неадекватно.

Ответы [ 6 ]

24 голосов
/ 18 октября 2010

Один из вариантов - включить в сохраненный хэш номер версии алгоритма - поэтому вы начинаете с алгоритма 0 (например, MD5) и сохраняете

0:ab0123fe

, а затем при обновлении до SHA-1 поднимаетеномер версии 1:

1:babababa192df1312

(нет, я знаю, что эти длины, вероятно, не верны).

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

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

20 голосов
/ 18 октября 2010

Отличный способ защитить все существующие пароли: использовать существующий хеш в качестве входных данных для нового и лучшего хэша пароля.

Таким образом, если ваши существующие хэши являются прямыми MD5 и вы планируете перейти к какой-либо форме PBKDF2 (или bcrypt , или scrypt ), тогда измените ваш хеш пароля:

PBKDF2( MD5( password ) )

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

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

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

А пока вы добавляете поле версии к паролям.

EDIT : криптография StackExchange содержит интересное обсуждение по этому методу.

9 голосов
/ 18 октября 2010

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

2 голосов
/ 18 октября 2010

Один из способов сделать это:

  • Введите новое поле для нового пароля
  • Когда пользователь входит в систему, проверьте пароль по старому хешу
  • Если все в порядке, хешируйте пароль в виде открытого текста с новым хешем
  • Удалить старый хеш

Тогда постепенно у вас будут только пароли с новым хешем

0 голосов
/ 18 октября 2010

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

0 голосов
/ 18 октября 2010

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

Вы можете попробовать это:

Сначала добавьте новый столбец в свою таблицу участников, или в какой таблице хранятся пароли.

ALTER TABLE members ADD is_pass_upgraded tinyint(1) default 0;

Далее, в вашем коде, который аутентифицирует пользователей, добавьте дополнительную логику (я использую PHP):

<?php
$username = $_POST['username'];
$password = $_POST['password'];

$auth_success = authenticateUser($username, $password); 
if (!$auth_success) {
    /**
     * They entered the wrong username/password. Redirect them back
     * to  the login page.
     */
} else {
    /**
     * Check to see if the member's password has been upgraded yet
     */
    $username = mysql_real_escape_string($username);
    $sql = "SELECT id FROM members WHERE username = '$username' AND is_pass_upgraded = 0 LIMIT 1";
    $results = mysql_query($sql);

    /**
     * Getting any results from the query means their password hasn't been
     * upgraded yet. We will upgrade it now.
     */
    if (mysql_num_rows($results) > 0) {
        /**
         * Generate a new password hash using your new algorithm. That's
         * what the generateNewPasswordHash() function does.
         */
        $password = generateNewPasswordHash($password);
        $password = mysql_real_escape_string($password);

        /**
         * Now that we have a new password hash, we'll update the member table
         * with the new password hash, and change the is_pass_upgraded flag.
         */
        $sql = "UPDATE members SET password = '$password', is_pass_upgraded = 1 WHERE username = '$username' LIMIT 1";
        mysql_query($sql);
    }
}

Ваша функция authenticateUser () должна быть изменена на что-то похожее на это:

<?php
function authenticateUser($username, $password)
{
    $username = mysql_real_escape_string($username);

    /**
     * We need password hashes using your old system (md5 for example)
     * and your new system.
     */
    $old_password_hashed = md5($password);
    $new_password_hashed = generateBetterPasswordHash($password);
    $old_password_hashed = mysql_real_escape_string($old_password_hashed);
    $new_password_hashed = mysql_real_escape_string($new_password_hashed);

    $sql = "SELECT *
        FROM members
        WHERE username = '$username'
        AND
        (
            (is_pass_upgraded = 0 AND password = '$old_password_hashed')
            OR
            (is_pass_upgraded = 1 AND password = '$new_password_hashed')
        )
        LIMIT 1";
    $results = mysql_query($sql);
    if (mysql_num_rows($results) > 0) {
        $row = mysql_fetch_assoc($results);
        startUserSession($row);
        return true;
    } else {
        return false;
    }
}

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

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

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