Как вы используете bcrypt для хеширования паролей в PHP?


1256

Время от времени я слышу совет: «Используйте bcrypt для хранения паролей в PHP, правила bcrypt».

А что есть bcrypt? PHP не предлагает никаких таких функций, Википедия болтает о утилите шифрования файлов, а поиски в Интернете показывают лишь несколько реализаций Blowfish на разных языках. Теперь Blowfish также доступен в PHP через mcrypt, но как это поможет с хранением паролей? Blowfish - это шифр общего назначения, он работает двумя способами. Если он может быть зашифрован, он может быть расшифрован. Пароли нуждаются в односторонней функции хеширования.

Какое объяснение?


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

59
@eykanal - на этой странице даже не упоминается bcrypt, а тем более объясните, что это такое .
Vilx-

8
@eykanal - я не прошу объяснения того, как это работает. Я просто хочу знать, что это такое. Потому что все, что я могу найти в сети под ключевым словом "bcrypt", никоим образом не может использоваться для хеширования паролей. Во всяком случае, не напрямую и не в PHP. Хорошо, теперь я понимаю, что это действительно пакет "phpass", который использует blowfish для шифрования вашего пароля с помощью ключа, полученного из вашего пароля (по сути, шифрование пароля самим собой). Но упоминание его как «bcrypt» вводит в заблуждение, и это то, что я хотел уточнить в этом вопросе.
Vilx-

3
@Vilx: Я добавил больше информации о том, почему bcryptэто односторонний хэш - алгоритм по сравнению со схемой шифрования в моем ответе . Существует целое заблуждение, что bcryptэто просто Blowfish, когда на самом деле он имеет совершенно другое расписание ключей, которое гарантирует, что простой текст не может быть восстановлен из текста шифра, не зная начального состояния шифра (соль, раунды, ключ).
Эндрю Мур

1
Также см. Портативный каркас хэширования паролей в Openwall (PHPass). Он защищен от ряда распространенных атак на пароли пользователей.
jww

Ответы:


1065

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

bcryptиспользует алгоритм Eksblowfish для хеширования паролей. В то время как этап шифрования Eksblowfish и Blowfish абсолютно одинаков, фаза расписания ключей Eksblowfish гарантирует, что любое последующее состояние зависит как от соли, так и от ключа (пароля пользователя), и никакое состояние не может быть предварительно вычислено без знания обоих. Из-за этого ключевого различия, bcryptалгоритм одностороннего хэширования. Вы не можете получить простой текстовый пароль, не зная соль, раунды и ключ (пароль). [ Источник ]

Как использовать bcrypt:

Использование PHP> = 5.5-DEV

Функции хеширования паролей теперь встроены непосредственно в PHP> = 5.5 . Теперь вы можете использовать password_hash()для создания bcryptхэша любой пароль:

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

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

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

Используя PHP> = 5.3.7, <5.5-DEV (также RedHat PHP> = 5.3.3)

Существует библиотека совместимости на GitHub создан на основе исходного кода из указанных выше функций , первоначально написанных на C, что обеспечивает такую же функциональность. Как только библиотека совместимости установлена, ее использование такое же, как указано выше (за исключением сокращенной записи массива, если вы все еще находитесь в ветке 5.3.x).

Использование PHP <5.3.7 (УСТАРЕЛО)

Вы можете использовать crypt()функцию для генерации bcrypt хэшей входных строк. Этот класс может автоматически генерировать соли и проверять существующие хэши по входным данным. Если вы используете версию PHP выше или равную 5.3.7, настоятельно рекомендуется использовать встроенную функцию или библиотеку compat . Эта альтернатива предоставляется только для исторических целей.

class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input){
    $hash = crypt($input, $this->getSalt());

    if (strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash){
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt(){
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if ($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if (strlen($bytes) < $count) {
      $bytes = '';

      if ($this->randomState === null) {
        $this->randomState = microtime();
        if (function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for ($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input){
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (true);

    return $output;
  }
}

Вы можете использовать этот код следующим образом:

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

Кроме того, вы также можете использовать Portable PHP Hashing Framework .


7
@ The Wicked Flea: Извините, что разочаровал вас, но mt_rand()также отображается с использованием текущего времени и текущего идентификатора процесса. Пожалуйста, смотрите GENERATE_SEED()в/ext/standard/php_rand.h .
Эндрю Мур

53
@Mike: Давай, это именно по этой причине!
Эндрю Мур

14
Для тех, кто думает, что им нужно изменить начало строки $ salt в функции getSalt, в этом нет необходимости. $ 2a $ __ является частью соли CRYPT_BLOWFISH. Из документов: «Blowfish хэширует с солью следующим образом:« $ 2a $ », двухзначный параметр стоимости,« $ »и 22 цифры из алфавита».
Джвин

18
@MichaelLang: Хорошая вещь crypt()проверяется и проверяется тогда. Приведенный выше код вызывает PHP crypt(), который вызывает crypt()функцию POSIX . Весь код выше делает больше - генерирует случайную соль (которая не должна быть криптографически безопасной, соль не считается секретной) перед вызовом crypt(). Может быть, вам следует провести небольшое исследование, прежде чем вызывать волка.
Эндрю Мур

31
Обратите внимание, что этот ответ, хотя и хороший, начинает показывать свой возраст. Этот код (как и любая реализация PHP, на которую опирается crypt()) подвержен уязвимости безопасности до 5.3.7 и (очень незначительно) неэффективен после 5.3.7 - подробности соответствующей проблемы можно найти здесь . Также обратите внимание, что новый API хеширования паролей ( обратная компат-библиотека ) теперь является предпочтительным методом реализации хеширования паролей bcrypt в вашем приложении.
DaveRandom

295

Итак, вы хотите использовать bcrypt? Потрясающие! Однако, как и в других областях криптографии, вы не должны делать это самостоятельно. Если вам нужно беспокоиться о чем-то вроде управления ключами, хранения солей или генерации случайных чисел, вы делаете это неправильно.

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

Посмотрим правде в глаза, криптография это сложно.

Оставьте это для экспертов. Оставьте это людям, чья работа состоит в том, чтобы поддерживать эти библиотеки. Если вам нужно принять решение, вы делаете это неправильно.

Вместо этого просто используйте библиотеку. Несколько существуют в зависимости от ваших требований.

Библиотеки

Вот разбивка некоторых из наиболее распространенных API.

PHP 5.5 API - (доступно для 5.3.7+)

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

function register($username, $password) {
    $hash = password_hash($password, PASSWORD_BCRYPT);
    save($username, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    if (password_verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

На самом деле, он призван быть чрезвычайно простым.

Ресурсы:

Zend \ Crypt \ Password \ Bcrypt (5.3.2+)

Это еще один API, похожий на PHP 5.5 и имеющий аналогичную цель.

function register($username, $password) {
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    $hash = $bcrypt->create($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    if ($bcrypt->verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Ресурсы:

PasswordLib

Это немного другой подход к хешированию паролей. Вместо того, чтобы просто поддерживать bcrypt, PasswordLib поддерживает большое количество алгоритмов хеширования. Это в основном полезно в тех случаях, когда вам необходимо поддерживать совместимость с устаревшими и разрозненными системами, которые могут находиться вне вашего контроля. Поддерживает большое количество алгоритмов хеширования. И поддерживается 5.3.2+

function register($username, $password) {
    $lib = new PasswordLib\PasswordLib();
    $hash = $lib->createPasswordHash($password, '$2y$', array('cost' => 12));
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $lib = new PasswordLib\PasswordLib();
    if ($lib->verifyPasswordHash($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Ссылки:

  • Исходный код / ​​Документация: GitHub

PHPASS

Это слой, который поддерживает bcrypt, но также поддерживает довольно сильный алгоритм, который полезен, если у вас нет доступа к PHP> = 5.3.2 ... Он фактически поддерживает PHP 3.0+ (хотя и не с bcrypt).

function register($username, $password) {
    $phpass = new PasswordHash(12, false);
    $hash = $phpass->HashPassword($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $phpass = new PasswordHash(12, false);
    if ($phpass->CheckPassword($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Ресурсы

Примечание: не используйте альтернативы PHPASS, которые не размещены на openwall, это разные проекты !!!

О компании BCrypt

Если вы заметили, каждая из этих библиотек возвращает одну строку. Это из-за того, как BCrypt работает внутри. И есть тонна ответов об этом. Вот подборка, которую я написал, которую я не буду здесь копировать / вставлять, но буду ссылаться на:

Заворачивать

Есть много разных вариантов. Что вы выбираете, зависит от вас. Тем не менее, я НАСТОЯТЕЛЬНО рекомендую вам использовать одну из перечисленных выше библиотек для решения этой проблемы.

Опять же, если вы используете crypt()напрямую, вы, вероятно, делаете что-то не так. Если ваш код использует hash()(или md5()или sha1()) напрямую, вы почти наверняка делаете что-то не так.

Просто используйте библиотеку ...


7
Соль должна генерироваться случайным образом, однако она не должна поступать из безопасного случайного источника. Соль не секрет . Возможность угадать следующую соль не оказывает реального влияния на безопасность; пока они поступают из достаточно большого пула данных, чтобы генерировать различные соли для каждого закодированного пароля, у вас все в порядке. Помните, что соль предназначена для предотвращения использования радужных таблиц, если ваши хеши попадают в плохие руки. Они не секрет.
Эндрю Мур

7
@AndrewMoore абсолютно правильно! Однако соль должна обладать достаточной энтропией, чтобы быть статистически уникальной. Не только в вашем приложении, но и во всех приложениях. Так что mt_rand()имеет достаточно высокий период, но начальное значение составляет всего 32 бита. Таким образом, использование mt_rand()эффективно ограничивает вас только 32 битами энтропии. Который благодаря проблеме дня рождения означает, что у вас есть 50% -й шанс столкновения только на 7 000 сгенерированных солей (глобально). Так как bcryptпринимает 128 битов соли, лучше использовать источник, который может предоставить все 128 битов ;-). (при 128 битах вероятность столкновения составляет 50% при хеше 2e19) ...
ircmaxell

1
@ircmaxell: «достаточно большой пул данных». Однако ваш источник не обязательно должен быть ОЧЕНЬ ВЫСОКИМ источником энтропии, достаточно высоким для 128 бит. Однако, если вы исчерпали все доступные источники (у вас нет OpenSSL и т. Д.), И ваш единственный запасной вариант - mt_rand (), он все равно лучше альтернативы (которая является rand ()).
Эндрю Мур

4
@AndrewMoore: абсолютно. Не спорю, что. Только это mt_randи uniqid(и, следовательно, lcg_valueи rand) не первый выбор ...
ircmaxell

1
ircmaxell, большое спасибо за библиотеку password_compat для 5.3.xx, раньше она нам не нужна, но сейчас мы делаем это на php-сервере 5.3.xx, и спасибо за четкий совет не пытаться делать эту логику себя.
Lizardx

47

Вы получите достаточно информации в «Радужных таблицах»: что нужно знать о безопасных схемах паролей или портативной среде хеширования паролей PHP .

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


7
Примените все, что вы хотите, пользователям удастся испортить и использовать один и тот же пароль на нескольких вещах. Таким образом, вы должны максимально защитить его или реализовать что-то, что позволит вам не хранить пароль (SSO, openID и т. Д.).
Арх

41
Нет. Хеширование паролей используется для защиты от одной атаки: кто-то украл вашу базу данных и хочет получить логин и пароли в виде открытого текста.
Арх

4
@Josh K. Я рекомендую вам попытаться взломать несколько простых паролей после того, как они настроены через phpass, поэтому для его вычисления на вашем веб-сервере требуется от 1 до 10 мс.
Арх

3
Согласовано. Но тип пользователя, который будет использовать qwerty в качестве пароля, также является типом пользователя, который будет отмечать любой сложный, где он (и злоумышленники) могут легко его прочитать. Что делает использование bcrypt, так это то, что, когда ваш БД становится публичным против вашей воли, тем пользователям, у которых есть пароль, например ^ | $$ & ZL6- £, будет сложнее, чем если бы вы использовали sha512 за один проход.
Арх

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

36

Вы можете создать односторонний хеш с помощью bcrypt, используя crypt()функцию PHP и передавая соответствующую соль Blowfish. Наиболее важным из всего уравнения является то, что A) алгоритм не был скомпрометирован и B) вы правильно заполняете каждый пароль . Не используйте соль для всего применения; это открывает все ваше приложение для атаки из одного набора таблиц Rainbow.

PHP - функция Crypt


4
Это правильный подход - используйте crypt()функцию PHP , которая поддерживает несколько различных функций хеширования паролей. Убедитесь, что вы не используете CRYPT_STD_DESили CRYPT_EXT_DES- любой из других поддерживаемых типов в порядке (и включает bcrypt, под именем CRYPT_BLOWFISH).
Кафе

4
У SHA действительно есть и параметр стоимости, с помощью опции «раундов». Когда я использую это, я также не вижу причин отдавать предпочтение bcrypt.
Питер Эннес

3
На самом деле, один SHA-1 (или MD5) пароля по-прежнему легко переборчив, с солью или без соли (соль помогает против радужных таблиц, а не против перебора). Используйте bcrypt.
Пауло Эберманн

Меня беспокоит, что все говорят «bcrypt», когда имеют в виду php's crypt ().
Sliq

3
@Panique Почему? Алгоритм называется bcrypt . cryptпредоставляет несколько хэшей паролей, причем bcrypt соответствует CRYPT_BLOWFISHконстанте. Bcrypt в настоящее время является самым мощным алгоритмом, поддерживаемым, cryptа некоторые другие, которые он поддерживает, довольно слабые.
CodesInChaos

34

Изменить: 2013.01.15 - Если ваш сервер будет поддерживать его, используйте вместо этого решение martinstoeckli .


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

function blowfishCrypt($password,$cost)
{
    $chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt=sprintf('$2y$%02d$',$cost);
//For PHP < PHP 5.3.7 use this instead
//    $salt=sprintf('$2a$%02d$',$cost);
    //Create a 22 character salt -edit- 2013.01.15 - replaced rand with mt_rand
    mt_srand();
    for($i=0;$i<22;$i++) $salt.=$chars[mt_rand(0,63)];
    return crypt($password,$salt);
}

Пример:

$hash=blowfishCrypt('password',10); //This creates the hash
$hash=blowfishCrypt('password',12); //This creates a more secure hash
if(crypt('password',$hash)==$hash){ /*ok*/ } //This checks a password

Я знаю, что это должно быть очевидно, но, пожалуйста, не используйте «пароль» в качестве пароля.


3
Создание соли может быть улучшено (используйте случайный источник ОС), в противном случае это выглядит хорошо для меня. Для более новых версий PHP лучше использовать 2yвместо 2a.
martinstoeckli

использовать в mcrypt_create_iv($size, MCRYPT_DEV_URANDOM)качестве источника для соли.
CodesInChaos

Я более подробно рассмотрю mcrypt_create_iv (), когда у меня появится момент, если ничего другого не должно немного улучшить производительность.
Джон Халка

2
Добавить кодировку Base64 и перевести на пользовательский алфавит bcryptиспользует. mcrypt_create_iv(17, MCRYPT_DEV_URANDOM), str_replace('+', '.', base64_encode($rawSalt)),$salt = substr($salt, 0, 22);
CodesInChaos

1
@JonHulka - посмотрите на пакет совместимости PHP [Строка 127], это простая реализация.
martinstoeckli

29

Версия 5.5 PHP будет иметь встроенную поддержку BCrypt, функции password_hash()и password_verify(). На самом деле это всего лишь обертки вокруг функции crypt(), и они облегчат ее правильное использование. Он заботится о генерации безопасной случайной соли и обеспечивает хорошие значения по умолчанию.

Самый простой способ использовать эти функции:

$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Этот код хеширует пароль с помощью BCrypt (алгоритм 2y), генерирует случайную соль из случайного источника ОС и использует параметр стоимости по умолчанию (на данный момент это 10). Вторая строка проверяет, соответствует ли введенный пользователем пароль уже сохраненному хеш-значению.

Если вы хотите изменить параметр стоимости, вы можете сделать это следующим образом, увеличив параметр стоимости на 1, удвоив необходимое время для вычисления значения хеш-функции:

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));

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

Для PHP версии 5.3.7 и новее существует пакет совместимости от того же автора, который создал эту password_hash()функцию. Для PHP версий до 5.3.7 нет поддержки crypt()с 2y, алгоритмом юникода безопасного Bcrypt. Вместо этого можно заменить его на 2a, что является лучшей альтернативой для более ранних версий PHP.


3
После того, как я прочитал это, моей первой мыслью было: «Как вы храните полученную соль»? После просмотра документов функция password_hash () в итоге генерирует строку, в которой хранятся метод шифрования, соль и сгенерированный хэш. Таким образом, он просто хранит все, что ему нужно, в одной строке для работы функции password_verify (). Просто хотел упомянуть об этом, так как это может помочь другим, когда они видят это.
jzimmerman2011

@ jzimmerman2011 - Точно, в другом ответе я попытался объяснить этот формат хранения на примере.
martinstoeckli

7

Современное мышление: хэши должны быть самыми медленными, а не самыми быстрыми. Это подавляет атаки радужного стола .

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

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


Я думаю, они предполагают, что злоумышленнику уже удалось украсть мою БД с помощью других средств, и теперь пытается вывести пароли, чтобы попробовать их на PayPal или что-то в этом роде.
Vilx-

4
На полпути до 2012 года, и этот ответ все еще сомнительный, как алгоритм медленного хеширования предотвращает атаки радужных таблиц? Я думал, что случайная соль диапазона байтов сделала? Я всегда думал, что скорость алгоритма хеширования определяет, сколько итераций они могут отправить против хэша, который они получили от вас за определенное время. Кроме того, НИКОГДА НЕ ЗАБИРАЙТЕ ПОЛЬЗОВАТЕЛЯ НА НЕУДАЧИХ ПОПЫТКАХ ВХОДА, поверьте мне, ваши пользователи будут сыты по горло, часто на некоторых сайтах мне нужно входить в систему почти 5 раз, иногда больше, прежде чем я запомнил свой пароль для него. Также второй уровень прохода не работает, хотя двухэтапная аутентификация с кодом мобильного телефона могла бы.
Саммайе

1
@ Sammaye Я бы с этим согласился. Я установил блок на 5 неудачных попыток входа в систему, прежде чем быстро повысить его до 7, а затем 10, теперь он сидит на 20. Ни у одного обычного пользователя не должно быть 20 неудачных попыток входа в систему, но его достаточно мало, чтобы легко остановить атаки методом подбора
Брюс Олдридж,

@BruceAldridge Лично я думаю, что было бы лучше сделать ваш скрипт приостановленным на случайное время после, скажем, 7 неудачных входов в систему и показывать капчу вместо блокировки. Блокировка - очень агрессивный ход.
Саммай

1
@ Sammaye Я согласен, что постоянные блоки плохие. Я имею в виду временный блок, который увеличивается с количеством неудачных попыток.
Брюс Олдридж

7

Вот обновленный ответ на этот старый вопрос!

Правильный способ хэширования паролей в PHP начиная с 5.5 - с password_hash(), и правильный способ их проверки - с помощью password_verify(), и это все еще верно в PHP 8.0. Эти функции по умолчанию используют хеши bcrypt, но были добавлены другие более сильные алгоритмы. Вы можете изменить коэффициент работы (эффективно, насколько "сильное" шифрование) с помощью password_hashпараметров.

Однако, хотя он все еще достаточно силен, bcrypt больше не считается современным ; появился улучшенный набор алгоритмов хеширования паролей под названием Argon2 , с вариантами Argon2i, Argon2d и Argon2id. Разница между ними (как описано здесь ):

Argon2 имеет один первичный вариант: Argon2id и два дополнительных варианта: Argon2d и Argon2i. Argon2d использует доступ к памяти в зависимости от данных, что делает его пригодным для криптовалют и приложений для проверки работоспособности без угроз со стороны побочных временных атак. Argon2i использует независимый от данных доступ к памяти, который предпочтителен для хеширования паролей и получения ключей на основе паролей. Argon2id работает как Argon2i для первой половины первой итерации в памяти и как Argon2d для остальной, обеспечивая таким образом защиту от атак по побочному каналу и экономию затрат методом "грубой силы" из-за компромиссов времени и памяти.

Поддержка Argon2i была добавлена ​​в PHP 7.2, и вы запрашиваете ее следующим образом:

$hash = password_hash('mypassword', PASSWORD_ARGON2I);

и поддержка Argon2id была добавлена ​​в PHP 7.3:

$hash = password_hash('mypassword', PASSWORD_ARGON2ID);

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

Совершенно отдельно (и несколько избыточно), libsodium (добавлено в PHP 7.2) также обеспечивает Argon 2 хэширование с помощью sodium_crypto_pwhash_str ()и sodium_crypto_pwhash_str_verify()функций, которые работают примерно так же, как PHP Модульное. Одной из возможных причин их использования является то, что PHP иногда может быть скомпилирован без libargon2, что делает алгоритмы Argon2 недоступными для функции password_hash; В PHP 7.2 и выше всегда должен быть включен libsodium, но это может и не произойти - но по крайней мере есть два способа использования этого алгоритма. Вот как вы можете создать хеш Argon2id с помощью libsodium (даже в PHP 7.2, в котором иначе отсутствует поддержка Argon2id)):

$hash = sodium_crypto_pwhash_str(
    'mypassword',
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

Обратите внимание, что он не позволяет указать соль вручную; это часть принципа libsodium - не позволяйте пользователям устанавливать параметры в значения, которые могут поставить под угрозу безопасность - например, ничто не мешает вам передавать пустую солт-строку в password_hashфункцию PHP ; libsodium не позволяет тебе делать глупости!



1

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

функция password_hash () используется для создания нового хэша пароля. Он использует надежный и надежный алгоритм хеширования. Функция password_hash () очень совместима с функцией crypt (). Поэтому хэши паролей, созданные crypt (), могут использоваться с password_hash () и наоборот. Функции password_verify () и password_hash () просто обертывают вокруг функции crypt (), и они значительно упрощают ее точное использование.

СИНТАКСИС

string password_hash($password , $algo , $options)

Следующие алгоритмы в настоящее время поддерживаются функцией password_hash ():

PASSWORD_DEFAULT PASSWORD_BCRYPT PASSWORD_ARGON2I PASSWORD_ARGON2ID

Параметры: эта функция принимает три параметра, как указано выше и описано ниже:

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

Пример :

Input : echo password_hash("GFG@123", PASSWORD_DEFAULT); Output : $2y$10$.vGA19Jh8YrwSJFDodbfoHJIOFH)DfhuofGv3Fykk1a

Ниже программы иллюстрируют функцию password_hash () в PHP:

<?php echo password_hash("GFG@123", PASSWORD_DEFAULT); ?>

ВЫВОД

$2y$10$Z166W1fBdsLcXPVQVfPw/uRq1ueWMA6sLt9bmdUFz9AmOGLdM393G

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.