За последние полгода мы обнаружили и описали в отчётах очень похожую уязвимость аутентификации у трёх разных клиентов. Во всех трёх случаях библиотека JWT была обновлена до последней версии, и во всех трёх проблема крылась не в самой библиотеке, а в переданных ей параметрах проверки. В этой статье мы разбираем, откуда берётся уязвимость, как она выглядит в продуктивной среде и как устранить её окончательно, — с позиции защищающейся стороны.
Коротко о главном
JSON Web Token (JWT) можно сравнить с сессионным билетом, который сервер выпускает и подписывает. При каждом запросе сервер проверяет подпись и доверяет идентификатору пользователя внутри билета. Вся модель держится на одном условии: подпись проверяется всегда, при любых обстоятельствах и правильным ключом. Как только проверка ослабевает, содержимому билета доверять уже нельзя.
Чаще всего мы сталкивались с тремя ошибками конфигурации.
1. Алгоритм берётся из самого токена
Код проверки выбирал алгоритм, ориентируясь на заголовок самого токена. Безопасный подход прямо противоположен: сервер сам фиксирует ожидаемый алгоритм и применяет его, что бы ни было указано в токене.
Правило: передавайте функции проверки допустимые алгоритмы явным списком. Никогда не доверяйте алгоритму, который предлагает токен.
2. Смешение симметричных и асимметричных ключей
В ряде приложений проверка выполнялась с помощью асимметричного открытого ключа, однако код был настроен настолько нестрого, что допускал и симметричную проверку. Открытый ключ по определению доступен всем; если разрешить симметричную проверку, это общедоступное значение может занять место секрета подписи.
Решение однозначное: каждая конечная точка должна принимать только одно семейство алгоритмов. Если вы используете семейство RS/ES, полностью отклоняйте семейство HS на уровне проверки.
3. Отсутствие проверки срока действия и отзыва
Даже при корректной подписи отдельной проблемой остаётся приём билета, срок действия которого истёк или который был отозван при выходе из системы. Мы встречали случаи, когда поле exp не проверялось, а токен не аннулировался на стороне сервера после выхода пользователя.
Как мы это исправили
У всех трёх клиентов исправление оказалось небольшим, но решающим:
- Допустимые алгоритмы передаются в вызов проверки явным списком.
- Любое семейство алгоритмов, кроме ожидаемого, отклоняется.
- Поля
exp,issиaudвключены в обязательную проверку. - При критических изменениях привилегий выпускается новый токен, а старый аннулируется на стороне сервера.
Чек-лист для вашей команды
- Список алгоритмов функции проверки задаёте вы или его определяет токен?
- Если вы подписываете асимметричным ключом, отклоняет ли уровень проверки симметричное семейство без исключений?
- Проверяются ли срок действия, издатель и получатель при каждом запросе?
- Действительно ли старые сессионные токены становятся недействительными при выходе и смене пароля?
Если хотя бы на один из этих четырёх вопросов вы не можете ответить «да», ваш уровень аутентификации заслуживает целевой проверки. Именно эту цепочку мы и разбираем в ходе тестирования на проникновение.