XSS: типы атак и экранирование вывода

XSS (Cross-Site Scripting) — уязвимость, при которой в страницу попадает чужой контент, который браузер исполняет как часть сайта.

Суть проблемы

Браузер доверяет коду, который пришёл со страницы. Если приложение вставляет пользовательский ввод в HTML без обработки, ввод может содержать разметку, которую браузер выполнит. Как и в SQL-инъекции, корень — смешение данных и кода, только теперь код — это HTML/JavaScript.

Три типа XSS

  • Stored (хранимый) — вредный ввод сохраняется на сервере (например, в комментарии) и показывается всем посетителям.
  • Reflected (отражённый) — ввод возвращается сразу в ответе, обычно через параметр ссылки.
  • DOM-based — манипуляция происходит целиком в браузере через небезопасную работу с DOM.

Защита: экранирование вывода

Главный приём — экранировать данные при выводе в HTML. Опасные символы заменяются на безопасные «сущности»: < становится &lt;, >&gt;. Тогда браузер показывает текст, а не выполняет его как разметку.

import html

# Пользователь ввёл строку, похожую на тег
user_comment = "<b>Привет</b> & пока"

# Небезопасно было бы вставить как есть.
# Безопасно — экранировать перед выводом в HTML:
safe = html.escape(user_comment)
print("Будет показано как текст:")
print(safe)

После экранирования строка отображается как обычный текст, а не превращается в живой тег.

Дополнительные слои

  • Шаблонизаторы (Jinja2, Django templates) экранируют вывод автоматически — не отключайте это без причины.
  • Content Security Policy (CSP) — заголовок, ограничивающий, какие скрипты браузер вправе выполнять.
  • HttpOnly-куки — куки сессии недоступны из JavaScript, что снижает ущерб.
  • Для вставки в атрибуты, URL или JS-контекст нужны свои правила экранирования — контекст имеет значение.

Принцип тот же: считайте любой пользовательский ввод недоверенным и обрабатывайте его при выводе.

Проверьте себя
1. Чем отличается хранимый (stored) XSS от отражённого (reflected)?
AНичем, это одно и то же
BХранимый сохраняется на сервере и показывается многим пользователям, отражённый возвращается сразу в ответе на конкретный запрос
CХранимый работает только в Chrome
DОтражённый опаснее, потому что шифрует данные
Поддержать проект