Top-5 атак на JWT
JWT — мощный инструмент для авторизации, но его легко неправильно использовать. По данным OWASP и Snyk Security Reports, 60% уязвимостей JWT в production вызваны типичными ошибками реализации, не дырами в самом стандарте. Разберём топ-5 атак и как от них защититься.
1. None Algorithm Attack
Самая известная атака. JWT-стандарт включает алгоритм «none» — токен без подписи. В ранних версиях библиотек (jsonwebtoken до 9.0) это принималось по умолчанию.
Атака:
1. Берём оригинальный токен от пользователя:
eyJhbGciOiJIUzI1NiI... (header: HS256)
2. Меняем header на:
{"alg":"none","typ":"JWT"}
3. Меняем payload (например, добавляем admin):
{"sub":"123","role":"admin","exp":...}
4. Удаляем signature (оставляем только пустую часть):
header.payload.
5. Сервер проверяет: "alg":"none" → подпись не нужна → принимает!
Защита:
jwt.verify(token, secret, {
algorithms: ["HS256"] // ← обязательно указать!
});2. Algorithm Confusion (HS vs RS)
Атакующий меняет алгоритм с RS256 на HS256, использует публичный ключ как HMAC secret.
Атака:
1. Сервер использует RS256 с публичным ключом для verify
2. Атакующий меняет alg на HS256
3. Подписывает HMAC-SHA-256 с публичным ключом как secret
4. Сервер думает что HS256, использует "secret" (publickey) для verify
5. Подпись валидна!
Защита:
Жёстко привязать алгоритм к ключу:
- Если ключ private RSA → только RS256
- Если HMAC secret → только HS256
В коде:
const algorithm = isRSAKey(key) ? "RS256" : "HS256";
jwt.verify(token, key, { algorithms: [algorithm] });3. Weak Secret
Если secret для HS256 — это слово «password» или «mysecret123», атакующий подберёт его за секунды.
Атака: $ jwt-cracker eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... [+] Trying password... [no] [+] Trying secret123... [no] [+] Trying mysecret... [MATCH!] Атакующий теперь может подделывать любые токены. Защита: 1. Минимум 256 бит = 32 байта случайных 2. Генерируйте через CSPRNG: $ openssl rand -hex 64 # 76b0e5a23f8d4c91b6e5... 3. Храните в env переменных, секретных хранилищах 4. Никогда не commitите в git!
4. Stolen Secret
Самая частая утечка — secret в git-истории, логах, error messages, dump памяти.
Где утекают secrets: ❌ Hard-coded в коде: const secret = "abc123"; ❌ В .env, который попал в git ❌ В commit истории (даже после удаления из текущего файла!) ❌ В Sentry / Datadog logs (попал из-за ошибки кода) ❌ В GitHub public gist / Pastebin ❌ В headers логов nginx ❌ В memory dump через debugging endpoint Защита: ✅ Используйте Vault, AWS Secrets Manager, Yandex Cloud Lockbox ✅ Pre-commit hooks: detect-secrets, gitleaks ✅ Rotate secrets каждые 90 дней ✅ Если есть подозрение что утёк — немедленный rotation ✅ Логируйте только safe-redacted токены: "eyJ...***"
5. Replay Attack
Украденный токен (через MITM, XSS, Phishing) используется атакующим до истечения exp.
Защита: 1. Короткий exp: 15 минут вместо 24 часов 2. Refresh token rotation 3. JTI (JWT ID) blacklist для немедленного отзыва 4. Привязка к IP (но проблема с мобильными — IP меняется) 5. Привязка к User-Agent (для критичных операций) 6. HTTPS обязателен — защита от MITM 7. HTTPOnly cookies — защита от XSS-кражи
Most JWT vulnerabilities arise not from the standard itself, but from misuse: weak secrets, accepting arbitrary algorithms, storing tokens insecurely on the client. Defence-in-depth requires careful implementation at every layer.— OWASP — JSON Web Token Cheat Sheet, 2024
Выбор алгоритма
Хранение токенов
На клиенте (браузер)
- localStorage — удобно, но уязвимо к XSS. Не используйте для access token.
- HTTPOnly Secure SameSite=Strict cookie — лучшее для refresh token. Недоступно из JS, защита от XSS.
- In-memory переменная — лучшее для access token. Сбрасывается при перезагрузке (получите новый через refresh).
- SessionStorage — компромисс между localStorage и in-memory. Сохраняется до закрытия вкладки.
На сервере
- Refresh tokens — в БД. С user_id, expires_at, family_id (для rotation), revoked флагом.
- JTI blacklist (для отзыва) — в Redis. Быстрая проверка на каждый запрос.
- Secrets — в Vault / AWS Secrets Manager / Yandex Cloud Lockbox. Никогда в env переменных production.
- Public keys (для RS256) — в JWKS endpoint. /.well-known/jwks.json — стандарт OAuth/OIDC.
Security Checklist
- ☐ Алгоритм явно указан в jwt.verify (whitelist)
- ☐ Secret минимум 256 бит, сгенерирован через CSPRNG
- ☐ Secret в Vault / Secrets Manager, не в коде
- ☐ Secret rotation процедура (раз в 90 дней)
- ☐ Access token exp ≤ 15 минут
- ☐ Refresh token в HTTPOnly Secure cookie
- ☐ Refresh token rotation (single-use)
- ☐ JTI blacklist для немедленного отзыва
- ☐ HTTPS only (нет HTTP)
- ☐ В payload нет sensitive данных (паролей, ПИН, паспорта)
- ☐ Логирование redacted: "eyJ...***"
- ☐ Pre-commit hooks для detect secrets в коде
- ☐ Алерты на массовые failed verify (брутфорс)
- OWASP — JSON Web Token Cheat Sheet. OWASP. cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html. 2024.
- RFC 7519 — JSON Web Token (JWT). IETF. datatracker.ietf.org/doc/html/rfc7519. 2015.
- Critical vulnerabilities in JSON Web Token libraries. Tim McLean / Auth0. auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries. 2015.
- JWT Best Current Practices. IETF RFC 8725. datatracker.ietf.org/doc/html/rfc8725. 2020.
