Разработчики любят писать микросервисы для
"перекладывания JSON". Стандарт устоявшийся и, как правило, не сулит проблем. Но так ли это на самом деле?
Возьмем небольшое приложение с двумя микросервисами:
—
Cart — реализует бизнес-логику корзины
—
Payment — используется для обработки платежей
Cart написан на
Python с
Flask и принимает ID товаров с их количеством. Попробуем отправить в него запрос с двумя одинаковыми ключами:
"cart": [
{
"id": 0,
"qty": 5
},
{
"id": 1,
"qty": -1,
"qty": 1
}
]
Сервис провалидирует
JSON в соответствии со схемой
jsonschema.validate(instance=data, schema=schema). Убедится, что
id: 0 <= x <= 10 and qty: >= 1. На этом этапе не будет ошибки (не смотря на то, что один из отправленных
qty не подходит под условие), поскольку
Flask использует стандартный
JSON-парсер из
Python, а тот сериализует данные, отдавая приоритет последнего ключа (
qty = 1).
Дальше провалидированный
JSON отправляется в микросервис
Payment.
А микросервис
Payment написан уже на
Go и использует другой парсер
buger/jsonparser. Он уже не валидирует
JSON (ведь валидация была на предыдущем шаге), но использует приоритет первого ключа (
qty = -1). Считает итоговую сумму
total = total + productDB[id]["price"].(int64) * qty и генерирует чек.
Мы смотрим в чек, который вернулся в ответе, и видим ошибку. Нам будет отправлено шесть товаров стоимостью
700 долларов, но с нас взяли только
300 долларов, из-за расчетов со вторым ключом.
Такие ошибки возникают из-за того, что существует много стандартов JSON:
1. json.org
2. IETF RFC 4627
3. ECMAScript 262
4. ECMA 404
5. IETF RFC 7158
6. IETF RFC 7159
7. JSON5
8. HJSON
И в каждом из них свои правила парсинга JSON: о том, как обрабатывать дублирующие ключи, что делать с большими числами с плавающей точкой, что считать валидным, а что нет. И на каждом из этих этапов могут возникнуть коллизии, позволяющие обходить средства защиты или вызывающие баги в бизнес логике.
Полезные ссылки:
— https://seriot.ch/json/parsing.html — большая таблица-сравнение: как разные парсеры обрабатывают разные значения.
— https://bishopfox.com/blog/json-interoperability-vulnerabilities — я рассказал только об одном баге, но их гораздо больше: здесь можно почитать обо всех остальных.
— https://github.com/a1phaboy/JsonDetect — расширение для
Burp для определения того, какой парсер используется.
Обсуждение 3
Обсуждение не доступно в веб-версии. Чтобы написать комментарий, перейдите в приложение Telegram.
Обсудить в Telegram