РНР-безопасность: где и как хранить пароли. Часть 2

в 13:46, , рубрики: password_hash, php, Блог компании OTUS. Онлайн-образование, информационная безопасность

Всем привет! На прошлой неделе мы опубликовали первую часть данной статьи, чем вызвали нешуточный холивар.

Одной из главных претензий было отсутствие в статье упоминания password_hash, как мы и обещали, вторую часть данного материала начнем как раз таки с хеширования пароля с помощью password_hash. Также напоминаем о том, что написание данной статьи было навеяно запуском новой группы по курсу «Backend-разработчик на PHP», но к программе обучения данный материал отношения не имеет.

РНР-безопасность: где и как хранить пароли. Часть 2 - 1

Подробнее о программе обучения можно будет узнать на дне открытых дверей, а на примере бесплатного вебинара по теме «ServerLess PHP», вы можете оценить формат проведения лекций.


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

Хеширование пароля с помощью password_hash

Эта функция создает хеш пароля в соответствии с теми параметрами, которые мы ей зададим. Она использует односторонний алгоритм.

Мы можем выбрать, какой тип алгоритма использовать, задав одну из констант по своему выбору:

  • PASSWORD_DEFAULT из PHP 5.5 использует Bcrypt в качестве алгоритма по умолчанию. Однако с течением времени это изменяется по мере обнаружения новых, более безопасных алгоритмов либо иных факторов.
  • PASSWORD_BCRYPT создает хеш crypt(). Обычно он содержит 60 символов, опознать его можно по идентификатору в формате "$2y$".
  • PASSWORD-ARGON2I Argon2 на данный момент является одним из наиболее безопасных алгоритмов хеширования. Он доступен только в том случае, если РНР был скомпилирован с Argon2.
  • PASSWORD_ARGON2ID Этот алгоритм хеширования также принадлежит к семейству Argon2 и задействует версию Argon2ID, а не I. Чтобы он работал, также необходимо, чтобы РНР был скомпилирован посредством Argon2.

У этой функции также есть необязательный параметр, который состоит из ассоциативного массива, принимающего несколько ключей в соответствии с выбранным алгоритмом.
Если вы предпочитаете использовать Bcrypt, ключ этой последовательности будет значением cost.

Если вы выберете алгоритм, который использует Argon2, ключами для ассоциативного массива будут: memory_cost (целое число, указывающее максимальное количество памяти, необходимое для вычисления хэша), time_cost (целое число, указывающее максимальное время, необходимое для вычисления хэша) и thread (другое целое число, указывающее количество потоков, используемых при вычислении хэша).

Не указывайте параметр salt в РНР 7.0, иначе получите предупреждение об устаревшем подходе.

Теперь мы знаем, какие элементы необходимы для использования функции password_hash(). Давайте посмотрим, как ее прописывать.

echo password_hash("MySuperPass", PASSWORD_DEFAULT);
$2y$10$TLayAY8ZaAZ9FE50EylGYO9oEgrb7gsw1yzJemHdBu1gOQfyWrEUm
$options = ['cost' => 12,];

echo password_hash("MySuperPass", PASSWORD_BCRYPT, $options);
$2y$12$jhmTbxAuZXVtX2y.Jc8iy.dW/NENqVCeq2vuoFI9/oa4./YlzhpYO

echo password_hash('rasmuslerdorf', PASSWORD_ARGON2I);
$argon2i$v=19$m=1024,t=2,p=2$YzJBSzV4TUhkMzc3d3laeg$zqU/1IN0/AogfP4cmSJI1vc8lpXRW9/S0sYY2i2jHT0

Сначала рекомендуется протестировать эту функцию на ваших серверах и настроить параметр cost таким образом, чтобы исполнение функции отнимало менее 100 миллисекунд в интерактивных системах.

Скрипт в вышеприведенном примере поможет вам задать оптимальное значение cost для вашего аппаратного оборудования.

Верификация пароля пользователя

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

Хешируя данные в соответствии с последними трендами безопасности, вы ничего не храните в зашифрованном виде, а ваш сервер спрятан в подвале 10-метровой глубины.

Что теперь?

Теперь вы должны позволить пользователям залогиниться в приложении. Для этого в РНР предусмотрена встроенная функция, которая проверяет соответствие пароля хешированной последовательности. Эта функция носит название password_verify(). Работает она примерно вот так:

$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Пароль верен!';
} else {
    echo 'Пароль не правильный!';
}

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

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

Эта функция работает благодаря тому, что на предыдущем шаге (когда мы хешировали пароль), значение, вернувшееся от password_hash, включало в себя используемый нами алгоритм, cost и salt.

Таким образом, нам доступна вся информация, необходимая для password_verify().

Алгоритм работы системы регистрации пользователей на РНР

Надеюсь, теперь вы понимаете, какие меры безопасности принимают РНР-разработчики при обращении с паролями.

Сначала необходимо проверить наличие post-запроса, а затем отобрать и подсчитать количество пользователей, чьи данные совпадают с введенными.

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

Заключение

Теперь вы знаете, как обеспечить безопасность своему приложению и как правильно обращаться с паролями. Следование полезным рекомендациям — это не просто стандарт, который вы должны соблюдать, а путь развития, следовать которому должно быть приятно.
Осваивайте новые техники по аналогии с тем, как вы только что ознакомились. Добавляйте дополнительный функционал и экспериментируйте с кодом до тех пор, пока не получите отличные скиллы по веб-разработке — будь то РНР или любой другой язык, открывающий перед вами не менее широкие возможности!

Читать первую часть

Автор: Дмитрий

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js