Як ви використовуєте bcrypt для хешування паролів у PHP?


1255

Раз у раз чую поради "Використовуйте bcrypt для зберігання паролів у PHP, правилах bcrypt".

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

Яке пояснення?


13
Це питання було вирішено раніше , і їх пропозиція щодо використання стандартної бібліотеки є чудовою. Безпека - справа складна, і, використовуючи пакет, розроблений кимось, хто знає, що, до біса, вони роблять, ви лише допомагаєте собі.
ейканал

59
@eykanal - ця сторінка навіть не згадує bcrypt, тим більше пояснює, що це таке .
Вількс-

8
@eykanal - я не прошу пояснення, як це працює. Я просто хочу знати, що це таке. Тому що все, що я можу викопати в мережі під ключовим словом "bcrypt", ні в якому разі не можна використовувати для хешування паролів. Не безпосередньо, так і не в PHP. Гаразд, на даний момент я розумію, що це дійсно пакет "phpass", який використовує "шум", щоб зашифрувати ваш пароль ключем, який виходить із вашого пароля (по суті, шифруючи сам пароль). Але посилання на це як "bcrypt" сильно вводить в оману, і саме це я хотів уточнити в цьому питанні.
Vilx-

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

1
Також див. Карту хешування паролів PHP Openwall (PHPass). Це посилено проти низки поширених атак на паролі користувачів.
jww

Відповіді:


1065

bcryptце алгоритм хешування, який можна масштабувати за допомогою апаратного забезпечення (за допомогою настроюваної кількості раундів). Його повільність і кілька раундів гарантують, що зловмисник повинен розгорнути великі кошти та обладнання, щоб мати змогу зламати ваші паролі. Додайте до цього солі за паролем ( 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";
// $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);

Крім того, ви можете також використовувати портативний PHP Hashing Framework .


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

53
@Mike: Вперед, це саме з цієї причини!
Ендрю Мур

14
Для тих, хто думає, що їм потрібно змінити початок рядка $ солі у функції getSalt, це не обов'язково. $ 2a $ __ є частиною солі CRYPT_BLOWFISH. З документів: "Хеширование Blowfish з сіллю наступним чином:" $ 2a $ ", двозначний параметр вартості" $ "та 22 цифри з алфавіту".
jwinn

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

31
Зауважте, що ця відповідь, хоча і хороша, починає показувати свій вік. Цей код (як і будь-яка реалізація PHP, на який покладається crypt()) підпорядковується вразливості безпеки до 5.3.7 та є (дуже незначно) неефективним після 5.3.7 - детальну інформацію про відповідну проблему можна знайти тут . Зауважте також, що новий API хешування паролів ( назад compat lib ) є кращим методом реалізації хешування паролів 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 \ Пароль \ 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 тис. Генерованих солей (у всьому світі). Оскільки 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, нам це раніше не потрібно, але зараз ми робимо це на 5.3.xx php-сервері, і дякую за чітку пораду не намагатися робити цю логіку себе.
Лізардкс

47

Ви отримаєте багато інформації в " Достатньо з таблицями веселки": що вам потрібно знати про безпечні схеми паролів або портативну структуру хешування паролів PHP .

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


7
Виконуючи все, що завгодно, користувачі зможуть накрутити і використовувати один і той же пароль для кількох речей. Таким чином, ви повинні максимально захистити його або реалізувати щось, що не дозволяє зберігати пароль (SSO, openID тощо).
Арх

41
Ні. Хешування паролів використовується для захисту від однієї атаки: хтось вкрав вашу базу даних і хоче отримати чіткий текст логін + паролі.
Арх

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

3
Домовились. Але той тип користувача, який буде використовувати qwerty як пароль, також є тим самим користувачем, який помітить будь-який складний десь він (і зловмисники) можуть легко його прочитати. Що стосується використання bcrypt, це те, що коли ваш db стає загальнодоступним проти вашої волі, вам буде важче дістатися до тих користувачів, у яких є пароль, наприклад ^ | $$ & ZL6- £, ніж якщо ви використовували sha512 за один прохід.
Арх

4
@coreyward варто зазначити, що робити це шкідливіше, ніж взагалі не блокувати; що легко вважається вектором "відмови в обслуговуванні". Просто почніть спамувати погані реєстрації на будь-яких відомих облікових записах, і ви можете порушити багатьох користувачів дуже і дуже легко. Краще відхилити (затримати) нападника, ніж прямо відмовити у доступі, особливо якщо це клієнт, який платить.
damianb

36

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

PHP - функція скріплення


4
Це правильний підхід - використовуйте crypt()функцію PHP , яка підтримує кілька різних функцій хешування паролів. Переконайтеся, що ви не використовуєте CRYPT_STD_DESабо CRYPT_EXT_DES- будь-який з інших підтримуваних типів є нормальним (і включає bcrypt під назвою CRYPT_BLOWFISH).
caf

4
У SHA дійсно є і параметр вартості через опцію "раунди". Використовуючи це, я також не бачу причин надавати перевагу bcrypt.
Пітер Еннес

3
Насправді, один SHA-1 (або MD5) пароля все ще легко піддається грубій силі, з сіллю або без неї (сіль допомагає проти райдужних столів, а не проти жорстокого насильства). Використовуйте bcrypt.
Paŭlo Ebermann

Мені стає тривожно, що всі, здається, говорять "bcrypt", коли мають на увазі крипту php ().
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, що використовується Unicode. Можна замість цього замінити на 2a, що є найкращою альтернативою для більш ранніх версій PHP.


3
Після того, як я прочитав це, моя перша думка полягала в тому, "як ти зберігаєш сіль, що утворюється"? Після покази через документи, функція password_hash () закінчується генеруванням рядка, який зберігає метод шифрування, сіль та створений хеш. Отже, він просто зберігає все необхідне в одній рядку для роботи функції password_verify (). Просто хотілося згадати про це, оскільки це може допомогти іншим, коли вони переглянуть це.
jzimmerman2011

@ jzimmerman2011 - Точно в іншій відповіді я спробував пояснити цей формат зберігання на прикладі.
martinstoeckli

7

Поточне мислення: хеші повинні бути найповільнішими, не найшвидшими. Це пригнічує атаки веселкового столу .

Також пов’язана, але застережлива: Зловмисник ніколи не повинен мати необмежений доступ до вашого екрана входу. Щоб запобігти цьому: Створіть таблицю відстеження IP-адрес, яка записує кожен звернення разом з URI. Якщо більше, ніж 5 спроб увійти з однієї і тієї ж 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);

Зміни для перевірки паролів не потрібно, оскільки отриманий хеш-рядок містить інформацію про те, які алгоритми, солі та фактори роботи використовувались під час його створення.

Зовсім окремо (і дещо надмірно), лібсодіум (доданий у PHP 7.2) також забезпечує хешування Argon2 за допомогою sodium_crypto_pwhash_str ()і sodium_crypto_pwhash_str_verify()функцій, які працюють так само, як і вбудовані PHP. Однією з можливих причин їх використання є те, що PHP іноді може бути скомпільовано без libargon2, що робить алгоритми Argon2 недоступними для функції password_hash; У PHP 7.2 і вище завжди повинен бути включений лібсодіум, але це може бути не так - але принаймні є два способи отримати цей алгоритм. Ось як можна створити хеш 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 (), і вони значно полегшують її точне використання.

SYNTAX

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

Наступні алгоритми підтримуються функцією password_hash ():

PASSWORD_DEFAULT PASSWORD_BCRYPT PASSWORD_ARGON2I PASSWORD_ARGON2ID

Параметри: Ця функція приймає три параметри, як було зазначено вище та описано нижче:

пароль : він зберігає пароль користувача. algo : це константа алгоритму паролів, яка використовується постійно, позначаючи алгоритм, який повинен використовуватися, коли відбувається хешування пароля. параметри : Це асоціативний масив, який містить параметри. Якщо це буде видалено і не включає, буде використана випадкова сіль, і буде використана вартість за замовчуванням. Повернене значення : Він повертає хешований пароль при успіху або False on fail.

Приклад :

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.