XSS: типы атак и экранирование вывода
XSS (Cross-Site Scripting) — уязвимость, при которой в страницу попадает чужой контент, который браузер исполняет как часть сайта.
Суть проблемы
Браузер доверяет коду, который пришёл со страницы. Если приложение вставляет пользовательский ввод в HTML без обработки, ввод может содержать разметку, которую браузер выполнит. Как и в SQL-инъекции, корень — смешение данных и кода, только теперь код — это HTML/JavaScript.
Три типа XSS
- Stored (хранимый) — вредный ввод сохраняется на сервере (например, в комментарии) и показывается всем посетителям.
- Reflected (отражённый) — ввод возвращается сразу в ответе, обычно через параметр ссылки.
- DOM-based — манипуляция происходит целиком в браузере через небезопасную работу с DOM.
Защита: экранирование вывода
Главный приём — экранировать данные при выводе в HTML. Опасные символы заменяются на безопасные «сущности»: < становится <, > — >. Тогда браузер показывает текст, а не выполняет его как разметку.
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Отражённый опаснее, потому что шифрует данные