JWT Authentication: Взлом слабой криптографии
В этой лаборатории сервер использует JWT для авторизации, но совершает сразу две критические ошибки: использует слабый секретный ключ и доверяет заголовку alg.
hardgolangPro
Задача
# JWT: обход аутентификации через приём небезопасного алгоритма подписи
## Сценарий
Вы — аудитор безопасности **SecureShop**. Приложение использует JWT-токены для аутентификации: при входе сервер выдаёт токен, который хранится в cookie `token` и проверяется при каждом запросе. Команда уверена, что эндпоинт-валидатор JWT настроен корректно: используется стандартная библиотека golang-jwt, секрет хранится на сервере, токен подписывается HMAC. По данным внутреннего аудита, в админ-панели хранится конфиденциальная метка, доступная только пользователям с ролью администратора; её требуется извлечь, имея только обычную учётную запись.
## Цель
1. Изучите структуру JWT-токена, выдаваемого сервером после логина обычного пользователя — какие поля в нём есть, какой алгоритм указан в заголовке, какие claims контролируются сервером.
2. Найдите способ создать токен с произвольными claims без знания серверного секрета — иначе говоря, обойти криптографическую проверку подписи.
3. Получите доступ к админ-панели и извлеките флаг.
## Теория
JWT-токен состоит из трёх base64url-частей, разделённых точками: заголовка (с указанием алгоритма подписи), payload (с claims — данными о пользователе) и подписи. Подпись доказывает, что claims не изменялись после выдачи токена. Однако спецификация JWT исторически включала алгоритм `none`, обозначающий «токен без подписи» — он был введён для случаев передачи через уже защищённые каналы (mTLS, локальный IPC), но в публичных HTTP-API стал источником массовых уязвимостей: если сервер принимает токены с `alg: none`, проверка подписи фактически отсутствует, и атакующий может предъявить любой токен с любыми claims.
**Уязвимый паттерн:**
```go
// Список разрешённых алгоритмов включает "none" — подпись не проверяется
token, _ := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
if t.Method.Alg() == "none" {
return jwt.UnsafeAllowNoneSignatureType, nil
}
return jwtSecret, nil
}, jwt.WithValidMethods([]string{"HS256", "none"}))
```
Различные JWT-библиотеки имеют разные реакции на `alg: none` по умолчанию: одни принимают (старые версии), другие требуют явного opt-in (как `WithValidMethods` в golang-jwt/v5). Уязвимость возникает, когда разработчик добавляет `"none"` в whitelist алгоритмов — обычно по ошибке, копируя пример с docs или решая «специальный случай для тестирования».
## Точка входа атаки
| Параметр | Значение |
|----------|----------|
| Учётные данные обычного пользователя | `demo` / `demo` |
| Эндпоинт логина | `POST /login` (выдаёт cookie `token` с JWT) |
| Привилегированный эндпоинт | `GET /admin` (требует `role: admin` в JWT-payload) |