FlawOpen

flawopen.com/SSTI/Jinja2

Безопасна ли функция Jinja2 render_template_string()?

CWE-1336: Внедрение шаблонов на стороне сервераСправочная страница
Краткий ответ

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

УЯЗВИМЫЙ
# All four are the same bug
render_template_string(f"Hi {name}")
render_template_string("Hi " + name)
render_template_string("Hi %s" % name)
render_template_string("Hi {}".format(name))

# A very common real-world shape:
@app.errorhandler(404)
def not_found(e):
    return render_template_string(
        f"<h1>No such page: "
        f"{request.path}</h1>"
    ), 404
# The URL path is attacker-controlled.
ИСПРАВЛЕНО
# Template is a literal; the user value
# arrives as a named context variable
render_template_string(
    "Hi {{ name }}", name=name
)

# Better still, a real template file
render_template("greeting.html",
                name=name)

# For the 404 case, no template
# evaluation is needed at all:
return render_template("404.html",
                       path=request.path), 404

Чем опасен исходный текст шаблона под контролем атакующего

По умолчанию Flask предоставляет шаблонам глобальные объекты приложения, например config, request и session. Если атакующий контролирует исходный текст шаблона, Jinja вычисляет выражения с объектами, доступными в этом окружении. Последствия зависят от того, какие объекты и возможности открывает приложение. Безвредное арифметическое выражение может подтвердить факт вычисления, но само по себе не доказывает выполнение кода или доступность конкретных данных.

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

CVE-2024-56201 — отдельный случай

Эта уязвимость компилятора Jinja отличается от обычной SSTI и не является её обязательным условием: CVE-2024-56201 затрагивает Jinja 3.0.0–3.1.4, если атакующий может контролировать и содержимое, и имя шаблона. При таком условии было возможно выполнить произвольный код Python даже с включённой песочницей. Исправление вошло в Jinja 3.1.5. Изучите бюллетень и обновите библиотеку, если приложение принимает шаблоны или имена от атакующего.

Где это встречается

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

Частые вопросы

Защищает ли от этого автоэкранирование?

Нет. Автоэкранирование преобразует выведенные значения для снижения риска XSS. Оно не мешает компилировать пользовательскую строку как исходный текст шаблона. Эти меры относятся к разным этапам обработки.

Что делать, если пользователям нужно задавать шаблоны, например для писем?

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

Как найти проблему в существующем коде?

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

Источники

См. также SSTI: причина, последствия и защита от инъекции в шаблон Что такое серверная инъекция в шаблон? SSTI в FreeMarker и Velocity: безопасные шаблоны