XSS: межсайтовый скриптинг и экранирование вывода
XSS возникает, когда данные пользователя попадают на страницу как код, а не как текст.
XSS (Cross-Site Scripting) — уязвимость, при которой непроверенные данные выводятся на страницу так, что браузер исполняет их как часть HTML или JavaScript.
Суть проблемы
Заметьте параллель с SQL-инъекцией: там ввод смешивался с командой к базе, здесь — с разметкой страницы. Если приложение берёт, например, комментарий пользователя и вставляет его в HTML без обработки, то текст вроде «обычный отзыв» отобразится нормально, а текст, содержащий теги, браузер воспримет как настоящую разметку и выполнит вложенный скрипт.
Опасность в том, что такой скрипт выполняется в браузере другого пользователя, от его имени: может украсть его cookie сессии, подменить страницу, выполнить действия за него.
Типы XSS
| Тип | Как попадает |
| Хранимый (stored) | вредоносный ввод сохраняется в базе и показывается всем (комментарий, профиль) |
| Отражённый (reflected) | приходит в параметре ссылки и сразу возвращается в ответе |
| DOM-based | скрипт на странице сам небезопасно вставляет данные в DOM |
Главная защита: экранирование вывода
Ключевая идея — экранировать вывод: при вставке данных в HTML спецсимволы заменяют на безопасные сущности, чтобы браузер показал их как текст, а не разметку. Символ < превращается в <, > — в > и так далее. Тогда введённые теги отобразятся буквами, а не выполнятся.
Запустите пример простого экранирования (модуль html входит в стандартную библиотеку):
import html
user_input = "<b>Привет</b> и кавычка \" вот"
safe = html.escape(user_input)
print("Как ввёл пользователь:", user_input)
print("После экранирования :", safe)
Вывод:
Как ввёл пользователь: <b>Привет</b> и кавычка " вот После экранирования : <b>Привет</b> и кавычка " вот
После экранирования угловые скобки превратились в < и > — браузер покажет их как текст, а не как теги, и никакой скрипт не выполнится.
Контекст имеет значение
Экранировать нужно под контекст, куда вставляются данные: внутри HTML-текста — одни правила, внутри атрибута — другие, внутри URL или JavaScript — третьи. К счастью, современные шаблонизаторы (в шаблонах фреймворков) экранируют вывод по умолчанию. Опасность появляется, когда разработчик намеренно отключает экранирование («вставить как сырой HTML») для непроверенных данных.
Дополнительные слои
- Content Security Policy (CSP). Заголовок, который говорит браузеру, откуда разрешено грузить и исполнять скрипты. Даже при пропущенном XSS он может не дать скрипту выполниться.
- HttpOnly на cookie сессии. Тогда даже выполнившийся скрипт не прочитает cookie и не украдёт сессию.
- Валидация ввода. Полезна, но главная защита именно на выводе: один и тот же ввод безопасен в тексте и опасен в HTML.
Итог
- XSS — это ввод, который браузер исполняет как код страницы.
- Главная защита — экранирование вывода под нужный контекст.
- Шаблонизаторы экранируют по умолчанию; опасно отключать это для непроверенных данных.
- CSP и HttpOnly-cookie — дополнительные слои на случай промаха.