Как использовать bcrypt для хэширования паролей в PHP?
время от времени я слышу совет "использовать bcrypt для хранения паролей в PHP, правила bcrypt".
но что такое bcrypt? PHP не предлагает никаких таких функций, Википедия лепечет о утилите шифрования файлов, а веб-поиск просто показывает несколько реализаций Blowfish на разных языках. Теперь Blowfish также доступен в PHP через mcrypt, но как это поможет с хранением паролей? Blowfish-это шифр общего назначения, он работает двумя способами. Если это может быть зашифрован, его можно расшифровать. Пароли нуждаются в односторонней функции хэширования.
каково объяснение?
9 ответов:
bcrypt- это алгоритм хеширования, который масштабируется с помощью аппаратного обеспечения (с помощью настраиваемого количества раундов). Его медлительность и несколько раундов гарантирует, что злоумышленник должен развернуть огромные средства и оборудование, чтобы иметь возможность взломать ваши пароли. Добавьте к этому per-password соль (bcryptтребуется соли), и вы можете быть уверены, что атака практически неосуществима без смехотворного количества средств или оборудования.
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"; // y$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // For example: // y$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a // Usage 2: $options = [ 'cost' => 11 ]; echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n"; // yDP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4Cчтобы проверить пароль, предоставленный пользователем, на существующий хэш, вы можете использовать
password_verify()такие как:<?php // See the password_hash() example to see where this came from. $hash = 'y$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq'; if (password_verify('rasmuslerdorf', $hash)) { echo 'Password is valid!'; } else { echo 'Invalid password.'; }использование PHP > = 5.3.7, = 5.3.3)
есть библиотека совместимости on GitHub создан на основе исходного кода вышеуказанных функций, первоначально написанных на языке C, который обеспечивает ту же функциональность. Как только библиотека совместимости установлена, использование такое же, как и выше (минус сокращенная нотация массива, если вы все еще находитесь на 5.3.икс филиал.)
использование PHP (не рекомендуется)
можно использовать
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('a$%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.
Итак, вы хотите использовать bcrypt? потрясающе! однако, как и в других областях криптографии, вы не должны делать это самостоятельно. Если вам нужно беспокоиться о чем-то вроде управления ключами, хранения солей или генерации случайных чисел, вы делаете это неправильно.
причина проста: это так тривиально легко испортить bcrypt. Фактически, если вы посмотрите почти на каждый фрагмент кода на этой странице, вы заметите, что он нарушает хотя бы один из этих общих проблемы.
посмотрите правде в глаза, криптография трудна.
оставьте это для экспертов. Оставьте это для людей, которые должны поддерживать эти библиотеки. Если вам нужно принять решение, вы делаете это неправильно.
вместо этого просто используйте библиотеку. Существует несколько в зависимости от ваших требований.
библиотеки
вот разбивка некоторых из наиболее распространенных API.
PHP 5.5 API - (доступно для 5.3.7+)
начиная с PHP 5.5, вводится новый API для хэширования паролей. Существует также библиотека совместимости оболочек, поддерживаемая (мной) для 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 } }действительно, он нацелен на то, чтобы быть чрезвычайно простым.
ресурсы:
- документы: on PHP.net
- Библиотеки Совместимость: на GitHub
- PHP RFC: on wiki.php.net
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 } }ресурсы:
- документы: на Zend
- Сообщение В Блоге:Хэширование Паролей С Помощью Zend Крипта
PasswordLib
это немного другой подход к хэширование паролей. Вместо того, чтобы просто поддерживать bcrypt, PasswordLib поддерживает большое количество алгоритмов хэширования. Это в основном полезно в контекстах, где вам нужно поддерживать совместимость с устаревшими и разрозненными системами, которые могут быть вне вашего контроля. Он поддерживает большое количество алгоритмов хеширования. И поддерживается 5.3.2+
function register($username, $password) { $lib = new PasswordLib\PasswordLib(); $hash = $lib->createPasswordHash($password, 'y$', 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 } }ресурсы
- код: cvsweb
- Сайт Проекта: на OpenWall
- обзор алгоритма на StackOverflow
Примечание: не используйте альтернативы PHPASS, которые не размещены на openwall, это разные проекты!!!
О BCrypt
если вы заметили, каждый из этих библиотек возвращает одну строку. Это из-за того, как BCrypt работает внутри. И есть тонна ответов об этом. Вот выбор, который я написал, что я не буду копировать/вставлять здесь, но ссылка на:
- Принципиальная Разница Между Алгоритмами Хэширования И Шифрования - объяснять терминологию и некоторые основные сведения о них.
- о реверсировании хэшей без радужных таблиц - в основном, почему мы должны использовать bcrypt в первую очередь...
- хранение осуществляется Хэши - в основном, почему соль и алгоритм включены в результат хэша.
- Как обновить стоимость хэшей bcrypt - в основном, как выбрать, а затем поддерживать стоимость хэша bcrypt.
- как хэшировать длинные пароли с помощью bcrypt - объяснение 72-символьного ограничения пароля bcrypt.
- как bcrypt использует соли
- лучшие практики соления и перца пароли - в принципе, не используйте "перец"
- перенос старых
md5пароли к bcryptЗавернуть
есть много различных вариантов. Что вы выберете, зависит от вас. Однако, я бы очень рекомендуется использовать одну из вышеуказанных библиотек для обработки этого для вас.
опять же, если вы используете
crypt()напрямую, вы, вероятно, делаете что-то неправильно. Если ваш код используетhash()(илиmd5()илиsha1()) непосредственно, вы почти определенно делаете что-то неправильно.просто используйте библиотеку...
вы получите много информации в Хватит Радужных Таблиц: Что Вам Нужно Знать О Безопасных Схемах Паролей или Portable PHP password hashing framework.
цель состоит в том, чтобы хэшировать пароль с чем-то медленным, поэтому кто-то, получающий вашу базу паролей, умрет, пытаясь перебить его (задержка 10 мс для проверки пароля ничего для вас, много для кого-то, кто пытается перебить его). осуществляется медленно и может использоваться с параметром, чтобы выбрать как медленно это.
вы можете создать односторонний хэш с bcrypt, используя PHP
crypt()функция и передача в соответствующей соли Blowfish. Наиболее важным из всего уравнения является то, что а) алгоритм не был скомпрометирован и Б)вы правильно солите каждый пароль. Не используйте соль для всего приложения; это открывает все ваше приложение для атаки из одного набора радужных таблиц.
Edit: 2013.01.15-если ваш сервер будет поддерживать его, используйте martinstoeckli это!--5--> вместо.
каждый хочет, чтобы сделать это более сложным, чем это. Функция crypt () выполняет большую часть работы.
function blowfishCrypt($password,$cost) { $chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; $salt=sprintf('y$%02d$',$cost); //For PHP < PHP 5.3.7 use this instead // $salt=sprintf('a$%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Я знаю, что это должно быть очевидно, но, пожалуйста, не используйте "пароль" в качестве пароля.
версия 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 и более поздних версий существует пакет обеспечения совместимости, от того же автора, что сделал
в качестве альтернативы можно использовать скрипт, специально разработанный, чтобы быть выше осуществляется Колин Персиваль в его бумаги. Существует Scrypt PHP расширение в PECL. В идеале этот алгоритм будет свернут в PHP, чтобы его можно было указать для функций password_* (в идеале как "PASSWORD_SCRYPT"), но этого еще нет.
текущее мышление: хэши должны быть самыми медленными, а не самыми быстрыми. Это подавляет Радужный таблице атаки.
также связанные, но меры предосторожности: злоумышленник никогда не должен иметь неограниченный доступ к экрану входа в систему. Чтобы предотвратить это: настройте таблицу отслеживания IP-адресов, которая записывает каждое попадание вместе с URI. Если более 5 попыток входа происходят с одного и того же IP-адреса в любой пятиминутный период, блок с объяснением. Вторичный подход это должно иметь двухуровневую схему паролей, как это делают банки. Установка блокировки для сбоев на втором проходе повышает безопасность.
сводка: замедление атакующего с помощью временных хэш-функций. Кроме того, заблокируйте слишком много доступов к вашему логину и добавьте второй уровень пароля.
на OAuth 2 пароль:
$bcrypt = new \Zend\Crypt\Password\Bcrypt; $bcrypt->create("youpasswordhere", 10)
Comments