Практическая ситуация: API-шлюз проверяет схему входного запроса, после чего передаёт его сервису. Должен ли сервис повторно валидировать данные на своей границе доверия?
Да. Сервис должен самостоятельно валидировать данные на своей границе доверия, даже если их уже проверил API-шлюз. Проверка шлюза снижает нагрузку и отсекает часть атак, но не превращает полученные данные в безусловно доверенные.
В монолитных системах часто существовал один внешний периметр, поэтому разработчики связывали безопасность с проверкой на входе приложения. В распределённых системах данные проходят через несколько компонентов, которые могут вызываться напрямую, масштабироваться независимо или изменяться разными командами.
Это привело к практическому принципу: каждый компонент должен защищать собственную границу доверия. Такой подход уменьшает зависимость безопасности сервиса от конкретного маршрута запроса и от корректности внешней инфраструктуры.
API-шлюз может быть обойдён через внутренний маршрут, другой шлюз, очередь, административный интерфейс или ошибку маршрутизации. Кроме того, правила шлюза могут измениться, быть неполными либо проверять только структуру данных, но не их допустимость для конкретной бизнес-операции.
Если сервис принимает данные без собственной проверки, атакующий или ошибочный внутренний компонент может передать некорректное значение. Последствия включают нарушение бизнес-ограничений, некорректные записи, обход защитных предположений и уязвимости в последующей обработке.
Сервис должен рассматривать входящие данные как недоверенные до завершения собственной проверки. На границе сервиса нужно проверять типы, обязательность, формат, диапазоны, размер, допустимые значения и ограничения, относящиеся именно к этой операции.
Важно разделять структурную и семантическую валидацию. Шлюз может проверить, что поле существует и имеет числовой тип, но только сервис обычно способен определить, допустимо ли это число для текущего пользователя, состояния объекта или бизнес-перехода.
Проверка должна выполняться до опасных действий: записи в базу данных, построения команд для внешних систем, обращения к файловой системе или запуска ресурсоёмких операций. После нормализации данных сервису следует работать с проверенным внутренним представлением, не полагаясь на повторную интерпретацию исходной строки.
Дублирование проверок создаёт некоторую стоимость: увеличивает задержку, требует синхронизации правил и может привести к расхождению сообщений об ошибках. Компромисс состоит в разделении ответственности: общие ограничения можно централизовать, но критические для конкретного сервиса правила должны оставаться под его контролем; общую библиотеку следует использовать как средство повторного использования, а не как единственную границу безопасности.
Интернет-магазин пропускал заказы через шлюз, который проверял, что поле количества является положительным целым числом. Внутренний сервис оформления заказа дополнительно принимал сообщения из очереди, куда имели доступ несколько других сервисов.
Рассматривались два варианта. Полагаться только на шлюз было проще и уменьшало дублирование, но оставляло сервис уязвимым к обходным маршрутам. Повторять все проверки в каждом компоненте повышало надёжность, однако создавало риск расхождения правил.
Выбрали смешанный подход: шлюз выполнял общую проверку размера и структуры запроса, а сервис заказа самостоятельно проверял диапазоны, доступность товара, состояние заказа и допустимость операции для вызывающего контекста. Для сообщений из очереди применялись те же правила на стороне сервиса.
В результате прямые и внутренние пути обработки получили одинаковые бизнес-гарантии, а изменения правил заказа не требовали синхронного обновления шлюза. При этом общие схемы использовались повторно, чтобы не дублировать исключительно технические проверки.
Нет. Схема подтверждает структуру и типы, но не обязательно подтверждает безопасность значения. Нужно отдельно проверять бизнес-инварианты, контекст операции, размер ресурса и допустимость перехода состояния.
Например, корректное по схеме количество товара может быть недопустимо из-за лимита заказа или отсутствия товара. Такие правила принадлежат сервису, который владеет соответствующим состоянием.
Она может привести к дублированию, но границы безопасности важнее полного устранения повторов. Единый источник можно сохранить для общих схем и ограничений, тогда как сервис обязан иметь независимое решение о том, можно ли выполнить конкретную операцию.
Следует также тестировать совместимость правил и явно фиксировать, какая проверка относится к шлюзу, а какая к сервису. Нельзя считать библиотеку или общий контракт заменой проверки на стороне владельца операции.
Нет, если доверие к этому сервису не является явно доказанным архитектурным условием. Даже аутентифицированный компонент может быть скомпрометирован, неправильно настроен или передать данные, корректные для своей задачи, но опасные для принимающего сервиса.
Принимающий сервис должен проверять собственные предположения, а при необходимости дополнительно проверять источник сообщения, целостность данных и контекст полномочий. Это не означает, что каждому компоненту нужно заново реализовывать всю систему идентификации, но критические для его операции ограничения он обязан контролировать сам.