Двухфакторная аутентификация и лучшие практики безопасности паролей
Вы создали веб-приложение, и пользователи регистрируются. Но действительно ли их учетные записи защищены? Слабые пароли и отсутствие двухфакторной аутентификации (2FA) — одни из самых простых способов для злоумышленников проникнуть в систему. В этом руководстве мы рассмотрим практические, не теряющие актуальности лучшие практики безопасности паролей и 2FA, которые вы можете внедрить уже сегодня.
Почему безопасность паролей по-прежнему важна
Несмотря на годы предупреждений, пароли остаются основным методом аутентификации для большинства веб-приложений. Злоумышленники знают это и атакуют пароли с помощью фишинга, credential stuffing и брутфорса. Один скомпрометированный пароль может привести к захвату учетной записи, краже данных и ущербу репутации.
Надежные политики паролей и 2FA значительно повышают планку для злоумышленников. Давайте рассмотрим, как правильно реализовать и то, и другое.
Хранение паролей: правильное хеширование
Никогда не храните пароли в открытом виде. Всегда хешируйте их с помощью надежного, медленного алгоритма, предназначенного для паролей. Быстрые хеши, такие как SHA-256, не подходят, поскольку они позволяют проводить быстрые брутфорс-атаки.
Рекомендуемые алгоритмы:
- Argon2id – победитель Password Hashing Competition, устойчив к атакам с использованием GPU и side-channel атакам.
- bcrypt – широко поддерживается, проверен временем и медленный по своей природе.
- scrypt – требователен к памяти, хорошо предотвращает атаки с аппаратным ускорением.
Пример использования bcrypt в Node.js:
const bcrypt = require('bcrypt');
const saltRounds = 12;
async function hashPassword(password) {
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
Всегда используйте уникальную соль для каждого пароля (большинство библиотек делают это автоматически). Настройте коэффициент стоимости так, чтобы хеширование занимало ~100-500 мс на вашем сервере.
Политики паролей, которые действительно помогают
Забудьте о сложных правилах вроде «должен содержать символ и цифру». Современные рекомендации (NIST SP 800-63B) советуют:
- Минимальная длина 8 символов, но поощряйте использование парольных фраз (например, 4+ случайных слова).
- Проверяйте по спискам скомпрометированных паролей (например, API Have I Been Pwned).
- Не требуйте принудительного периодического истечения срока действия, если только не подозревается компрометация.
- Разрешайте все печатные ASCII-символы и пробелы.
- Ограничивайте частоту попыток входа для предотвращения брутфорса.
Реализуйте простой индикатор надежности, который дает обратную связь, не блокируя легитимные пароли.
Методы двухфакторной аутентификации (2FA)
2FA добавляет второй фактор: то, что у вас есть (телефон, аппаратный ключ), или то, чем вы являетесь (биометрия). Вот распространенные методы, упорядоченные по уровню безопасности:
| Метод | Безопасность | Удобство |
|---|---|---|
| Аппаратные ключи безопасности (WebAuthn/FIDO2) | Высокая | Среднее |
| Приложения-аутентификаторы (TOTP) | Высокая | Высокое |
| Push-уведомления | Средняя | Высокое |
| SMS-коды | Низкая | Высокое |
SMS уязвим для подмены SIM-карты и перехвата. По возможности предпочитайте TOTP или WebAuthn.
Реализация 2FA на основе TOTP
TOTP (Time-based One-Time Password) — отличный баланс между безопасностью и удобством. Вот высокоуровневый рабочий процесс:
- Сгенерируйте секретный ключ для пользователя (например, 32 случайных байта, закодированных в base32).
- Создайте URI otpauth:// и отобразите QR-код для сканирования пользователем в приложении-аутентификаторе.
- Убедитесь, что пользователь может сгенерировать действительный код, прежде чем включать 2FA.
- Храните секрет безопасно (зашифрованным при хранении).
- Предоставьте резервные коды для восстановления учетной записи.
При входе, после проверки пароля, запросите код TOTP. Проверьте его с помощью библиотеки, такой как otplib или speakeasy.
const { authenticator } = require('otplib');
// Generate secret
const secret = authenticator.generateSecret();
// Verify token
const isValid = authenticator.verify({ token: userToken, secret });
Допускайте небольшое временное окно (например, ±1 интервал) для учета рассинхронизации часов.
WebAuthn: будущее аутентификации
WebAuthn (часть FIDO2) обеспечивает аутентификацию без пароля и второй фактор с использованием аппаратных ключей или платформенных аутентификаторов (Touch ID, Windows Hello). Он устойчив к фишингу, поскольку учетные данные привязаны к источнику.
Для реализации WebAuthn требуется:
- Генерация и проверка challenge на стороне сервера.
- Клиентский JavaScript с использованием WebAuthn API.
- Хранение открытых ключей и идентификаторов учетных данных для каждого пользователя.
Библиотеки вроде SimpleWebAuthn упрощают задачу. Хотя это сложнее, чем TOTP, WebAuthn обеспечивает самую надежную защиту.
Ограничение частоты запросов и блокировка учетной записи
Даже с 2FA необходимо предотвращать брутфорс-атаки на пароли. Реализуйте:
- Ограничение частоты запросов по IP и по учетной записи (например, 5 попыток в минуту).
- Экспоненциальную задержку после неудачных попыток.
- Блокировку учетной записи после повторных неудач с безопасным процессом разблокировки (например, подтверждение по email).
- CAPTCHA после нескольких неудач.
Будьте осторожны, чтобы не заблокировать легитимных пользователей навсегда; используйте временные блокировки и уведомляйте пользователя.
Безопасный сброс пароля
Процессы сброса пароля — распространенный вектор атак. Следуйте этим правилам:
- Используйте одноразовый токен с ограниченным сроком действия, отправляемый по email.
- Не раскрывайте, существует ли email в системе.
- Требуйте повторной аутентификации, если пользователь уже вошел в систему.
- Аннулируйте все сессии после сброса пароля.
Обучение пользователей без обвинений
Безопасность — это общая ответственность. Предоставьте четкие рекомендации:
- Используйте менеджер паролей для генерации и хранения уникальных паролей.
- Включайте 2FA везде, где возможно.
- Остерегайтесь фишинговых попыток.
Внутренние подсказки и специальная страница безопасности могут помочь.
FAQ
SMS-2FA лучше, чем отсутствие 2FA?
Да, SMS-2FA лучше, чем ничего, но она уязвима для подмены SIM-карты и перехвата. Для более надежной защиты предпочитайте TOTP или WebAuthn.
Как часто нужно менять алгоритмы хеширования паролей?
Менять не нужно, если только не обнаружена уязвимость. Однако вы можете перехешировать пароли при успешном входе, когда обновляете параметры (например, увеличиваете стоимость bcrypt).
Можно ли использовать 2FA с OAuth или социальным входом?
Да, но 2FA обычно управляется поставщиком удостоверений. Если вы используете социальный вход, убедитесь, что ваш собственный процесс восстановления учетной записи безопасен.
Готовы повысить безопасность вашего приложения? Начните с внедрения надежного хеширования паролей и 2FA на основе TOTP уже сегодня. Для получения дополнительных инструментов для разработчиков ознакомьтесь с нашим JSON Formatter для быстрой отладки ответов API.