Как хранить пароли?

Это один из классических вопросов на собеседовании AppSec специалисту.

Не хранить пароли

Лучший ответ: "пароли хранить не надо, потому что в 202X мы не должны запускать сервисы с паролями!". За это можно получить хороший плюс.

WebAuthn

Два стандарта для беспарольной аутентификации на сайтах, в мобильных и веб-приложениях: WebAuthn API и CTAP. Оба были одобрены Microsoft, Mozilla и Google. Как они работают: https://habrahabr.ru/post/353966/?utm_campaign=353966

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

Одна из проблем, почему это не получило должного распространения: невозможность шарить сессию между устройствами. Недавно появилась технология passkeys от Apple, возможно это решит проблему.

Вход по СМС или TOTP

Если все же надо

Но если все-таки вернуться к вопросу, то ожидается ответ в духе:

  • Хранить хеши-пароли с солью

    • В качестве хеш-функции использовать Argon2, PBKDF2, Bcrypt, Scrypt с оптимальным количеством раундов

    • Соль отдельная для каждого пользователя

  • Харденинг

    • например, использовать HSM (тут долгие холивары в каком режиме)

    • "pepper" — то, что добавляют к паролю в начало (соль в конце, грубо говоря)

    • Пароли-канарейки: простые пароли в базе, которые добавляются периодически для пользователей, которые в нормальной жизни никогда не будут авторизоваться под ними, если кто-то авторизуется с этим паролем — значит у вас унесли базу и можно будет предположить примерное время

Ответы — хранить соленный md5/sha1/sha256/sha512 — автоматически ставят жирный минус.

Защита от брутфорса

Защита от брутфорса (все пароли для одного пользователя, рейтлимиты и капчи) и обратного брутфорса (слабые пароли на всех пользователях)

Как защитить от RCE на бэкенде

Но также есть еще один вопрос, сложный, и ответ на него мало кто знает — ”А как нам хранить пароли так, что если атакующий получит RCE на бэкендах, в т.ч. root привилегии, то не сможет дампнуть табличку с хэшами?”

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

  • getSalt(user_id) — Вернет «соль» пароля на бэкенд по userId, который пытается войти. Бэкенд возьмет введенный юзером пароль и получит хэш с солью из базы

  • checkPassword(user_id, hashed_password) — Возвращает true/false на проверке хэша пароля на предыдущем шаге у user_id

Таким образом, забрать хеши не получится для локального перебора.

Еще нужна процедура на создание пользователя и смену пароля, то они также не позволяют select'нуть хэши паролей пользователей. Хорошая статья по теме (но там не всё): https://www.secjuice.com/secure-password-handling/

Last updated