АрхитектураАрхитектура безопасностиАрхитектор безопасности приложений

Как изолировать выполнение пользовательских шаблонов, чтобы компрометация исполнителя не дала доступ к данн...

Как изолировать выполнение пользовательских шаблонов, чтобы компрометация исполнителя не дала доступ к данным самого сервиса?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Пользовательские шаблоны следует выполнять в отдельном изолированном окружении с минимальными привилегиями, отдельной идентичностью, ограниченными ресурсами и запрещённым доступом к внутренним сервисам и секретам. Основной защитный механизм — песочница на границе между недоверенным кодом и доверенной частью системы.

Одной проверки синтаксиса недостаточно: шаблон может использовать уязвимость движка или вызвать разрешённую, но опасную операцию. Поэтому безопасность должна обеспечиваться архитектурной изоляцией, а не только фильтрацией содержимого.

Исторический контекст

Песочницы появились как способ безопасно выполнять код, которому нельзя полностью доверять: пользовательские сценарии, плагины, документы и содержимое веб-страниц. Исходная проблема состояла в том, что анализ входных данных не мог гарантировать отсутствие всех опасных конструкций и ошибок интерпретатора.

Изоляция процессов, виртуальных машин и контейнеров позволила отделить выполнение потенциально опасного кода от данных и привилегий основной системы. На практике песочница рассматривается не как абсолютная гарантия, а как дополнительная граница безопасности, снижающая последствия компрометации исполнителя.

Постановка проблемы

Шаблон может содержать обращения к файлам, переменным окружения, сетевым адресам или функциям движка, которые первоначально не считались опасными. Если исполнитель работает с правами основного сервиса, успешная атака на него может привести к чтению секретов, изменению данных, обращению к внутренним API или захвату других компонентов.

Даже полностью изолированный процесс может создать отказ в обслуживании: бесконечный цикл, чрезмерное потребление памяти, большое число сетевых запросов или генерацию огромного результата. Поэтому нужно защищать не только конфиденциальность и целостность, но и доступность.

Подробное решение

Исполнитель размещают за отдельной границей доверия. Обычно это отдельный процесс или рабочая нагрузка с собственной учётной записью, без доступа к секретам основного сервиса, с минимальными правами файловой системы и только необходимыми системными возможностями.

Сетевой доступ по умолчанию запрещают. Если шаблону действительно нужны внешние данные, разрешают только конкретные направления через контролируемый посредник; прямой доступ к адресному пространству внутренних сервисов, метаданным облачной платформы и административным интерфейсам должен быть закрыт.

Для ограничения последствий применяют следующие меры:

  • лимиты времени выполнения, памяти, размера результата и числа операций;
  • отдельную файловую систему, предпочтительно без права записи;
  • отдельную идентичность без доступа к рабочим данным сервиса;
  • запрет или строгий allowlist опасных функций движка;
  • изоляцию процессов, контейнеров или виртуальных машин с учётом их реальных границ защиты;
  • удаление временного окружения после выполнения;
  • журналирование запусков, отказов и превышений лимитов без записи секретов.

Фильтрация шаблона и статический анализ полезны как дополнительный слой, но не должны быть единственным барьером. Чем сложнее язык шаблонов и чем больше разрешённых функций, тем выше поверхность атаки и стоимость безопасного аудита.

Выбор уровня изоляции зависит от модели угроз. Для простых шаблонов без логики безопаснее использовать ограниченный декларативный формат, чем полноценный язык. Для недоверенного кода с высокой ценностью защищаемых данных может потребоваться отдельная виртуальная машина или специализированный изолированный исполнитель, а не только процесс внутри общего окружения.

Ситуация из практики

Платформа отчётности позволяла клиентам создавать шаблоны документов. Первый вариант выполнял их внутри процесса API-сервиса после удаления нескольких опасных конструкций. Он был простым и быстрым, но зависел от полноты фильтра и делил с шаблонами память, секреты и сетевые права приложения.

Второй вариант использовал отдельный контейнер с ограничениями ресурсов. Это уменьшало последствия компрометации, но всё ещё требовало корректной настройки прав контейнера, сетевой политики и самого узла; контейнер нельзя считать автоматически полной изоляцией.

Выбранное решение запускало каждый шаблон в отдельном краткоживущем исполнителе с собственной идентичностью, отключённым исходящим трафиком, только чтением входных данных через контролируемый канал и жёсткими лимитами. Для особо чувствительных отчётов применялась более сильная изоляция. В результате компрометация движка ограничивалась рабочим окружением одного запуска, хотя стоимость выполнения и операционная сложность выросли.

Что кандидаты часто упускают

1. Достаточно ли запретить опасные функции в языке шаблонов?

Нет. Фильтрация может пропустить неизвестную конструкцию, ошибку в анализаторе или неожиданную комбинацию разрешённых функций. Она полезна для уменьшения поверхности атаки, но должна дополняться изоляцией, отдельной идентичностью и ограничением доступа к ресурсам.

2. Защищает ли песочница от отказа в обслуживании?

Не сама по себе. Изоляция может не дать шаблону прочитать данные или выйти в сеть, но бесконечное выполнение всё равно способно занять процессор и память. Нужны тайм-ауты, лимиты памяти, размера результата, очереди заданий и параллелизма, а также корректное завершение исполнителя.

3. Можно ли передать исполнителю рабочие секреты, если сетевой доступ запрещён?

Это существенно увеличивает последствия возможного обхода изоляции и обычно неоправданно. Исполнителю следует передавать только минимальный набор данных, необходимых для конкретного задания, через контролируемый канал; секреты основной системы не должны попадать в его окружение. Если доступ к секрету неизбежен, его ограничивают отдельной идентичностью, коротким сроком действия и минимальным набором разрешений.