Хэширование паролей в PHP 5.5 с использованием нового API

Использование BCrypt является общепринятым и лучшим способом для хэширования паролей, но большое количество разработчиков по-прежнему используют старые и слабые алгоритмы, вроде MD5 и SHA1. Некоторые разработчики даже не используют соль для хэширования. Новый API хэширования в PHP 5.5 ставит своей целью привлечь внимание к BCrypt, упрощая работу с ним. В этой статье я расскажу об основах использования нового API для хеширования в PHP.

Новый API хэширования паролей предоставляет четыре простых функции:
  • password_hash() — используется для хэширования пароля.
  • password_verify() — используется для проверки пароля на соответствие хэшу.
  • password_needs_rehash() — используется для проверки необходимости создать новый хэш.
  • password_get_info() — возвращает имя алгоритма хеширования и различные параметры, используемые при хэшировании.


password_hash()


Хотя функция crypt() довольно безопасна, она, по мнению многих, слишком сложная. Некоторые разработчики, чтобы не возиться с ней, используют слабую соль и слабый алгоритм для генерирования хэша, например:
<?php
$hash = md5($password . $salt); // works, but dangerous

Но функция password_hash() позволяет упростить нашу жизнь и обезопасить наш код. Когда вам нужно получить хэш пароля, просто скормите его в эту функцию, и она вернет хэш, который можно хранить в базе данных.
<?php
$hash = password_hash($passwod, PASSWORD_DEFAULT);

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

Алгоритм по умолчанию, в настоящее время, BCrypt, но более сильный алгоритм может быть установлен по умолчанию, когда-нибудь в будущем, и, возможно, он будет генерировать большие строки. Если вы используете PASSWORD_DEFAULT в ваших проектах, обязательно храните хэш в колонке, размером больше 60 символов. Установка размера колонки до 255 может быть хорошим выбором. Вы также можете использовать PASSWORD_BCRYPT в качестве второго параметра. В этом случае результат всегда будет 60 символов.

Главное здесь в том, что вам не нужно заботиться о значении соли и стоимости вычисления хэша. Новый API будет делать это за вас. И соль является частью хэша, так что вам не придется хранить его отдельно. Если вы хотите использовать вашу собственную соль (или стоимость вычисления), вы можете сделать это путем передачи третьего аргумента функции:
<?php
$options = [
    'salt' => custom_function_for_salt(), //write your own code to generate a suitable salt
    'cost' => 12 // the default cost is 10
];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);

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

password_verify()


Теперь, когда вы видели, как генерировать хэши с новым API, давайте посмотрим, как проверить пароль. Мы просто берем хэш из базы, и пароль, введенный пользователем и передаем их в эту функцию. password_verify() возвращает true, если хэш соответствует указанному паролю.
<?php
if (password_verify($password, $hash)) {
    // Success!
}
else {
    // Invalid credentials
}

Соль является частью хэша и именно поэтому нам не придется возиться с ней отдельно.

password_needs_rehash()


Что делать, если вам нужно изменить соль или стоимость вычисления для сохраненных паролей? Например, вы решили усилить безопасность и увеличить стоимость вычисления или изменить соль. Или PHP изменил алгоритм хэширования, используемый по умолчанию. В этих случаях вы хотели бы изменить существующие хэши паролей. Функция password_needs_rehash() проверяет, использует ли хэш пароля конкретный алгоритм, соль и стоимость вычисления.
<?php
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {
    // the password needs to be rehashed as it was not generated with
    // the current default algorithm or not created with the cost
    // parameter 12
    $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);
 
    // don't forget to store the new hash!
}

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

password_get_info()


Функция password_get_info() принимает хэш и возвращает ассоциативный массив из трех элементов:
  • algo — константа, которая идентифицирует конкретный алгоритм
  • algoName — название используемого алгоритма
  • options — различные опции, используемые при генерации хэша


Заключение


Новый API хэширования паролей, безусловно, удобнее, чем возня с crypt(). Если ваш сайт в настоящее время работает на PHP 5.5, то я настоятельно рекомендуется использовать новое API хэширования. Те, кто используют PHP 5.3.7 (или более новой версии), могут использовать библиотеку под названием password_compat которая эмулирует это API и автоматически отключает себя при использовании PHP версии 5.5+.

Оригинал.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 13

    +5
    Кажется об этом уже писали.
      +1
      То есть теперь надо не только проверить пароль, но еще и проверить, а не изменился ли алгоритм.
      Не совсем понятно, что будет, если изменится PASSWORD_DEFAULT. password_verify($password, $hash) вернет FALSE? А что вернет password_needs_rehash($hash, PASSWORD_DEFAULT)?
        0
        Ни разу не писал на PHP, но почему-то кажется, исходя из наличия метода password_get_info(), что в $hash хранится алгоритм, и эти сведения используются в password_verify
          0
          password_verify — не зависит от PASSWORD_DEFAULT, так как алгоритм по которому получен хеш вместе с параметрами храниться в самой переменной $hash.

          Поэтому если password_verify вернул FALSE, то значит пароль не верный. А если пароль правильный, тогда можно сделать проверку не обновился ли алгоритм password_needs_rehash, и тогда сохранить новый хеш.
            0
            Спасибо за объяснение.
          0
          Что сложного то нашли в crypt? простая как две копейки
            –5
            <?php
            $hash = md5($password . $salt); // works, but dangerous
            

            А если так:
            $hash = md5($password .md5($salt));
            $hash = md5(md5($password) .md5($salt));
            
            ???
              +1
              Абсолютно то же самое
                –4
                Специально проверил:
                <?php
                $password 	= 'vnkG767dfd';
                $salt 		= 'vnsiRfdR45';
                
                $hash1 = md5($password . $salt); //43a47c25ddeb356f4f01889a06bb01ff
                $hash2 = md5($password .md5($salt));//ac34660393373c58cc33d295c2b8202b
                $hash3 = md5(md5($password) .md5($salt));//67ba6ba0ec1fa56c9857ccf75a462ce3
                

                Абсолютно не тоже самое…
                  0
                  С точки зрения безопасности — одинаково легко перестроить радужную таблицу по любому предложенному вами алгоритму.
                    +3
                    Я читал вашу первую статью. Из нее я не смог понять почему так делать бессмысленно(не зря я вопросы в конце поставил). Вот тут нашел полезный материал, теперь стало все более-менее понятно. Так что, да. Так как я спрашивал — лучше не делать.
                0
                1. Слишком быстро.
                2. md5 x md5 увеличивает вероятность коллизий.
                0
                Использующие phpldapadmin с этой функцией уже немного познакомились, благо связанная с этим проблема легко исправима.

                Only users with full accounts can post comments. Log in, please.