Автоэкранирование, безопасность и статика

Jinja по умолчанию экранирует выводимые значения — превращает опасные символы в безопасные. Это защита от XSS, одной из самых частых веб-уязвимостей.
Если пользователь введёт в имя <script>...</script>, а ты выведешь это как есть — чужой скрипт выполнится в браузере жертвы. Автоэкранирование Jinja превращает теги в безопасный текст. Отключать его — почти всегда ошибка.

XSS (межсайтовый скриптинг) — атака, при которой злоумышленник внедряет свой HTML/JS через пользовательский ввод. Jinja защищает автоматически: при выводе через {{ }} символы < > & " превращаются в HTML-сущности (&lt; и т.д.). Браузер покажет их как текст, а не выполнит как разметку.

<!-- если comment = "<script>alert(1)</script>" -->
<p>{{ comment }}</p>
<!-- в HTML попадёт безопасный текст, скрипт не выполнится -->

Автоэкранирование включено для шаблонов .html. Если ты точно знаешь, что значение — доверенный HTML (например, очищенный санитайзером), его можно вывести как разметку фильтром |safe. Но это осознанный риск: |safe на пользовательских данных = открытая дверь для XSS.

Статические файлы (CSS, JS, картинки) кладут в папку static и ссылаются через url_for:

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<img src="{{ url_for('static', filename='logo.png') }}">

Автоэкранирование — это причина, по которой Flask-приложения защищены от XSS по умолчанию, и ты должен понимать, когда эта защита может отключиться. Опасность не в самом |safe, а в его бездумном применении к данным, пришедшим от пользователя: комментарий, имя, описание профиля — всё это потенциальный носитель чужого скрипта. Правило простое: |safe допустим только для HTML, который ты сам сгенерировал или который прошёл через санитайзер вроде bleach, вырезающий опасные теги. Второй частый источник дыр — сборка HTML строками во view с последующей отдачей: так ты обходишь автоэкранирование вручную. Доверяй шаблонизатору и не выводи сырой пользовательский HTML.

Как работает под капотом

Экранирование — это замена опасных символов на сущности. Браузер декодирует сущности при отображении, но не исполняет их как теги. Поэтому <script> показывается буквами, а не запускается.

  Ввод пользователя:  <b>hi</b>
       │ autoescape
       ▼
  В HTML-ответе:      &lt;b&gt;hi&lt;/b&gt;
       │ браузер декодирует при показе
       ▼
  На экране:          <b>hi</b>   (как текст, не жирный)

Смоделируем экранирование вручную — увидишь, почему оно обезвреживает скрипт.

def escape(text):
    return (text
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace('"', "&quot;"))

dangerous = "<script>alert('xss')</script>"
print("сырой:    ", dangerous)
print("безопасный:", escape(dangerous))
# в HTML второй вариант покажется текстом, скрипт не выполнится

Запусти: теги превратились в безопасные сущности. Jinja делает это для каждого {{ }} автоматически — поэтому Flask-приложения защищены от XSS «из коробки», пока ты не злоупотребляешь |safe.

Частые ошибки

  • Лепить |safe на пользовательский ввод. Это прямая дыра XSS. |safe только для доверенного/очищенного HTML.
  • Собирать HTML строками во view и отдавать. Минуешь автоэкранирование — снова риск XSS.
  • Хардкодить пути к статике. /static/style.css ломается при смене настроек; используй url_for('static').

Best practices

  • Никогда не отключай автоэкранирование без крайней нужды.
  • Пользовательский HTML перед |safe прогоняй через санитайзер (например bleach).
  • Статика — всегда через url_for('static', filename=...).

Что запомнить

  • Jinja экранирует вывод {{ }} автоматически, защищая от XSS.
  • |safe отключает экранирование — только для доверенного/санитизированного HTML.
  • Не собирай HTML строками во view, минуя автоэкранирование.
  • Статику подключают через url_for('static', filename=...).

Итог: Jinja экранирует вывод автоматически, защищая от XSS; |safe — осознанное исключение для доверенного HTML; статика подключается через url_for('static'). Это закрывает блок про шаблоны — дальше формы и состояние.

Проверьте себя
1. Что делает автоэкранирование Jinja2?
AСжимает HTML
BПревращает опасные символы (< > &) в сущности, защищая от XSS
CШифрует страницу
DУдаляет пробелы
2. Когда допустимо применять фильтр |safe?
AВсегда, для красоты
BТолько к доверенному или очищенному санитайзером HTML
CК любому пользовательскому вводу
DНикогда, он удалён