Смена пароля — пропущенный шаг re-auth
Типичная реализация «смены пароля» от джуна:
app.post('/change-password', auth, async (req, res) => {
const { newPassword } = req.body;
await db.query(
'UPDATE users SET password = ? WHERE id = ?',
[hash(newPassword), req.user.id]
);
res.json({ message: 'Password changed successfully' });
});
На ревью всё выглядит правильно:
- есть middleware
auth— пользователь аутентифицирован; - пароль хешируется перед записью в БД;
- SQL через плейсхолдеры — injection закрыт;
- обновляется только
req.user.id— чужой аккаунт не тронут.
Критический шаг всё же пропущен — сервер не проверяет текущий пароль (и не требует второй фактор). Достаточно действующей сессии или токена, чтобы навсегда сменить пароль и выбить владельца из аккаунта.
Хеши, соль и атаки на пароли — устройство и надёжность паролей. Сессии, JWT и отзыв токенов — аутентификация и авторизация.
Что отсутствует
Re-authentication — повторное подтверждение личности перед чувствительной операцией.
Для смены пароля клиент должен прислать минимум:
currentPassword(илиoldPassword) — строка, которую знает только владелец;newPassword— новое значение.
Сервер сравнивает currentPassword с хешем в БД (bcrypt.compare, argon2.verify). Только после успеха — UPDATE.
| Проверка | Есть в коде джуна | Зачем |
|---|---|---|
Пользователь залогинен (auth) | Да | Базовый барьер |
| Новый пароль хешируется | Да | Защита at rest |
| Текущий пароль верен | Нет | Доказательство, что это владелец, а не украденная сессия |
| CSRF-токен (cookie-auth) | Нет | Защита от подделки запроса из браузера |
| Инвалидация других сессий | Нет | Старый украденный токен остаётся валидным |
Middleware auth отвечает на вопрос «кто делает запрос по токену?», но не на «владелец ли аккаунта прямо сейчас?». Украденная сессия для этого эндпоинта равносильна знанию пароля.
Атака — захват аккаунта через сессию
Сценарий session hijacking (перехват сессии):
- Жертва залогинена в сервисе.
- Атакующий получает session cookie или JWT — XSS на том же origin, вредонсное расширение, malware, утечка токена в лог, HTTP без TLS на публичном Wi‑Fi.
- Атакующий шлёт
POST /change-passwordс своимnewPassword. Знание старого пароля не нужно. - Пароль в БД меняется. Жертва не может войти со старым паролем.
- Атакующий входит с новым паролем (или продолжает пользоваться украденным токеном, если сессии не отозваны).
Это полный захват аккаунта (account takeover): не «прочитал профиль», а закрепил контроль сменой секрета.
См. также JWT — семь строк, которые обходят авторизацию — компрометированный bearer-токен даёт тот же эффект на stateless API.
Вторая дыра — CSRF при cookie-сессии
Если auth держится на cookie (sessionId, HttpOnly), браузер сам прикладывает cookie к POST /change-password с любого сайта, пока жертва залогинена.
Вредоносная страница:
<form action="https://bank.example/change-password" method="POST">
<input type="hidden" name="newPassword" value="pwned123!" />
</form>
<script>document.forms[0].submit();</script>
Жертва открыла вкладку — форма ушла с её cookie. Сервер видит валидную сессию и меняет пароль без текущего пароля и без CSRF-токена.
Митигация CSRF — в статье о безопасности приложений: SameSite, anti-CSRF token, для API — не полагаться только на cookie без дополнительных мер.
Проверка текущего пароля CSRF не заменяет (атакующий может подставить и его, если знает — но при hijack сценарии пароль как раз неизвестен). Нужны оба слоя там, где применимо.
Безопасная реализация
Минимальный каркас:
app.post('/change-password', auth, csrf, async (req, res) => {
const { currentPassword, newPassword } = req.body;
const user = await db.query('SELECT password_hash FROM users WHERE id = ?', [
req.user.id,
]);
const ok = await verifyPassword(currentPassword, user.password_hash);
if (!ok) {
return res.status(403).json({ error: 'Invalid current password' });
}
if (!isStrongEnough(newPassword)) {
return res.status(400).json({ error: 'Password too weak' });
}
await db.query('UPDATE users SET password = ? WHERE id = ?', [
hash(newPassword),
req.user.id,
]);
await revokeAllSessionsExcept(req.user.id, req.session.id);
res.json({ message: 'Password changed' });
});
Дополнительно (production):
- Письмо «пароль изменён» — пользователь заметит взлом;
- Rate limit на эндпоинт — против перебора
currentPassword; - 2FA / WebAuthn для смены пароля в чувствительных продуктах;
- Единый стиль ошибок — не раскрывать, существует ли email на
/reset-password(отдельная тема).
У аккаунтов «Войти через Google» локального пароля может не быть — тогда re-auth это redirect на IdP (prompt=login) или проверка свежести сессии (auth_time, max_age в OIDC).
Чек-лист
- Запрос содержит
currentPassword; сервер сверяет с хешем в БД. - При cookie-auth — CSRF-токен или
SameSite=Strict/Lax+ не GET для смены. - После смены — отзыв остальных сессий и refresh-токенов.
- Уведомление по email/SMS.
- Rate limiting на
/change-passwordи/login. - Новый пароль проходит политику сложности и не совпадает с текущим.
- Логирование события без записи паролей в plain text.
Связанные материалы
| Тема | Статья |
|---|---|
| Хеширование и атаки на пароли | Устройство и надёжность паролей |
| Отзыв JWT и «выйти везде» | Аутентификация и авторизация |
| CSRF | 8.07 / 113 — CSRF |
| Каталог угроз API | 8.07 / 128 |
| Регресс «смена пароля» | 7.05 / 128 — тест-кейсы |
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Основы информационной безопасности - роль политик, контроль доступа и базовые принципы защиты данных в корпоративных системах. Аутентификация и авторизация - уровни проверки личности, двухфакторная защита и разграничение прав доступа в информационных системах. Антивирусная защита и лечение заражений - как распознать компрометацию системы, локализовать угрозу и восстановить рабочее состояние. Риски открытых Wi-Fi сетей - как работают passive/active-сканирование и почему публичные точки доступа требуют дополнительных мер защиты. Надёжность паролей — хеширование, соль, менеджеры паролей и типы атак: перебор, словарь, credential stuffing, фишинг, MITM. Фаерволы и сетевые пакеты - как межсетевой экран анализирует трафик и применяет правила фильтрации для защиты инфраструктуры. SSH — это протокол безопасного удалённого доступа к компьютерным системам. DoS и DDoS — как перегружают сервер, ботнет и SYN-flood, уровни атаки L3–L7 и базовая защита. Опасная конфигурация jwt.verify в Node.js — alg none, подмена алгоритма RS256 на HS256, секрет из process.env на уровне модуля и безопасная проверка токена. Broken Access Control — проверка прав через query-параметр, cookie или заголовок с клиента; эксплуатация за секунду и серверная авторизация. Краткие итоги раздела "Основы информационной безопасности". Чек-лист раздела Основы информационной безопасности — вопросы для самопроверки в энциклопедии Вселенная IT.Основы информационной безопасности
Аутентификация и авторизация
Антивирусная защита и лечение заражённых систем
Риски открытых Wi-Fi сетей
Устройство и надёжность паролей
Фаерволы
Шифрование данных и протокол SSH
DDoS и отказ в обслуживании
JWT — семь строк, которые обходят авторизацию
Админка по ?isAdmin=true
Итоги
Чек-лист самопроверки