Аутентификация и сессии
Как пользователи доказывают, кто они, и как ты держишь их в системе, не отдавая атакующему ключи. Это самая атакуемая поверхность любого приложения.
Чек-лист
- Хешируй пароли медленным солёным алгоритмом. Используй bcrypt, scrypt или Argon2, никогда простой SHA или MD5, и никогда не храни пароли открытым текстом. Если ты можешь прочитать пароль пользователя, его сможет прочитать и атакующий, у которого есть твоя база.
- Ограничивай попытки входа и сброса. Лимит попыток на IP и на аккаунт (например, десять за пятнадцать минут), затем отвечай 429. Без этого перебор тривиален.
- Не раскрывай, какие email существуют. Вход, регистрация и сброс пароля должны возвращать один и тот же общий ответ независимо от того, существует аккаунт или нет, с одинаковым временем ответа и одинаковыми кодами статуса.
- Делай токены сброса и подтверждения короткоживущими и одноразовыми. Не дольше часа, аннулируются при использовании. Относись к ним как к паролям.
- Привязывай OAuth-поток к браузеру, который его начал. Если входишь через Google, GitHub или аналогичный сервис, сохрани значение
stateв cookie на стартовом запросе и сверь его при callback. Без этой привязки атакующий может отправить жертве ссылку, которая залогинит жертву в аккаунт атакующего (login-CSRF). См. API и запросы. - Проверяй ответ провайдера идентичности. Требуй подтверждённый email, проверяй audience и issuer токена и никогда не доверяй id, который прислал клиент.
- Если добавляешь многофакторную аутентификацию, закрой второй шаг за первым. Второй фактор должен быть доступен только после успешной проверки пароля, с одноразовым challenge, иначе пространство кодов можно перебрать отдельно.
- Истекай сессии и поддерживай отзыв. Задай разумное время жизни токена и сделай так, чтобы смена пароля инвалидировала все существующие сессии.
- Проверяй пароль по списку утёкших паролей (например, через k-anonymity API HIBP) при регистрации и сбросе.
Как тестировать
- Выполни пятьдесят неверных входов подряд и убедись, что тебя ограничивают.
- Сравни ответ на сброс для реального и несуществующего email. Они должны быть идентичны.
- Начни OAuth-вход в одном браузере, заверши в другом. Это должно не получиться.