ТестированиеТестирование безопасностиИнженер по тестированию безопасности приложений

Разберите обработчик, в котором пользователь задаёт содержимое шаблона. Какой основной риск должен подтверд...

Разберите обработчик, в котором пользователь задаёт содержимое шаблона. Какой основной риск должен подтвердить тестировщик?

function preview(request):
    template = request.query["template"]
    return render_template(template, {"name": "Alex"})
Проходите собеседования с ИИ помощником Hintsage

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

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

Тест следует начинать с безвредного выражения, характерного для используемого шаблонизатора, например {{7*7}}. Если в ответе появляется 49, а не исходный текст, пользовательский ввод исполняется как шаблон, что подтверждает уязвимость.

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

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

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

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

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

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

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

Сначала нужно установить, действительно ли функция интерпретирует ввод как шаблон, а не просто вставляет его в заранее заданную страницу. Для этого используются безопасные диагностические выражения и маркеры, например арифметическое выражение синтаксиса конкретного движка. Простое отражение строки {{7*7}} без вычисления не доказывает SSTI.

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

Надёжное исправление — не принимать шаблон от пользователя. Приложение должно выбрать шаблон из фиксированного набора, а пользовательское значение передать как данные:

function preview(request): value = request.query["name"] return render_template("preview.html", {"name": value})

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

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

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

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

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

  1. Чем SSTI отличается от XSS?

    XSS обычно выполняется в браузере жертвы, когда пользовательское значение попадает в HTML, JavaScript или другой клиентский контекст. SSTI выполняется на сервере во время обработки шаблона; XSS может быть её последствием, но эти уязвимости проверяются на разных этапах и имеют разные границы воздействия.

  2. Достаточно ли запретить символы шаблонного синтаксиса?

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

  3. Всегда ли подтверждённая SSTI означает выполнение команд на сервере?

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