В логе шлюза принят токен с alg равным none — найдите и исправьте дефект
Шлюз API логирует каждый принятый токен. Эта запись сделана для запроса, вернувшего 200, и в ней же показан вызов проверки, который выполнил шлюз.
Ограничения:
- издатель подписывает все продовые токены алгоритмом
RS256и публикует ключи проверки - шлюз обязан отклонять любой токен, который не может проверить криптографически
- исправление не должно зависеть от чтения токена до выбора способа проверки
[gw] token accepted
header {"alg":"none","typ":"JWT"}
payload {"sub":"1042","role":"admin","exp":1893456000}
verify jwt.decode(rawToken) # claims взяты прямо из результата
outcome 200 GET /admin/users
Найдите и исправьте уязвимость.
Шлюз раскодирует токен вместо проверки, поэтому токен без алгоритма не несёт подписи и всё равно принимается. Проверяйте фиксированным алгоритмом и ключом издателя, отвергайте любое иное значение alg, а claims читайте только после этого.
- ✗Читать header
alg, чтобы решить, как проверять токен - ✗Вызывать помощник раскодирования, полагая, что он проверяет и подпись
- ✗Доверять claim
roleиз токена, который вообще не проверялся
- →Почему принимаемый алгоритм должен фиксировать сервер, а не токен?
- →Что добавить, чтобы находить в этих логах другие случаи приёма непроверенных токенов?
jwt.decode лишь разбирает и раскодирует строку — подпись он не проверяет. Токен с alg равным none подписи не несёт вовсе, поэтому шлюз принял role со значением admin, которое никто не подтверждал. Это не проблема самого токена, а отсутствие шага проверки.
Правильное исправление — вызвать проверку с алгоритмом и ключом, заданными на сервере, и не позволять токену выбирать способ собственной проверки. Любое другое значение alg отвергается, и claims читаются только после успешной проверки.
const claims = jwt.verify(rawToken, issuerPublicKey, {
algorithms: ['RS256'],
issuer: 'https://idp.example.com',
audience: 'api://gateway',
});
Дополнительно стоит завести правило детекта на принятые токены без подтверждённой подписи — такая запись в логе должна быть алертом, а не строкой уровня info.