Как предотвратить XSS (Cross‑Site Scripting): практическое руководство

Cross‑Site Scripting (XSS) — один из самых опасных векторов атак в вебе. Злоумышленники вставляют вредоносный код в страницы, и он выполняется в браузерах посетителей. В результате можно украсть сессии, перенаправить пользователя, выполнить действия от его имени или изменить содержимое страницы.
Этот материал объясняет практические приёмы защиты XSS на трёх уровнях вывода данных: HTML, JavaScript (включая innerHTML) и свойства DOM. Также приведены дополнительные методики, чеклисты и тесты для команд.
Что такое XSS — одно‑два предложения
XSS — это когда данные из внешнего источника (URL, форма, API) попадают в HTML/JS/DOM без корректного кодирования или валидации и выполняются в браузере.
Основные принципы защиты
- Отделяйте вход (валидация/нормализация) от вывода (кодирование/экранирование).
- Никогда не доверяйте данным от клиента.
- Используйте проверенные библиотеки для очистки HTML/DOM.
- Внедряйте Content Security Policy (CSP) и безопасные заголовки.
Как предотвратить XSS с помощью HTML
XSS часто происходит, когда приложение позволяет пользователям вставлять HTML‑теги. Пример гостевой книги: посетитель пишет имя и сообщение, которое отображается всем.
Атака: злоумышленник вставляет:
Если сайт просто вставляет пользовательский текст в страницу без экранирования, скрипт выполнится.
Решение: при выводе в HTML экранируйте специальные символы: <, >, &, “ и ‘. Для большинства языков и шаблонных движков есть готовые функции (например, htmlspecialchars в PHP, escapeHtml в многих фреймворках).
Пример безопасного вывода в шаблоне (псевдокод):
{{ user_input }}
{{ user_input | escape_html }}Важно: отличайте экранирование для HTML от экранирования для атрибутов, JavaScript и URL.
Как предотвратить XSS с помощью JavaScript (innerHTML и подобное)
В JavaScript опасно использовать innerHTML, document.write() и другие методы, которые парсят строку как HTML. Рассмотрим пример:
Если параметр search в URL содержит:
filename.php?search=a” alert(“The XSS!”); f=”
То итоговый код будет исполняться и приведёт к выполнению alert(). Аналогичная техника — закрывающий тег скрипта в параметре:
filename.php?search=";FatihЧтобы избежать этого:
- Избегайте innerHTML для вывода непроверенных строк. Используйте textContent или createTextNode, которые вставляют текст без парсинга HTML.
- Если нужно вставлять HTML, пропускайте его через проверенную библиотеку очистки (например, DOMPurify) и строго ограничивайте допустимые теги/атрибуты.
- Экранируйте кавычки при вставке в атрибуты через JavaScript.
Пример безопасной замены innerHTML:
const el = document.getElementById('print');
// безопасно: вставляет текст, а не HTML
el.textContent = userInput;
// если нужен HTML — очищаем библиотекой
el.innerHTML = DOMPurify.sanitize(userInput);Как предотвратить XSS через DOM‑атрибуты и URL
Иногда пользовательские данные используются как значения атрибутов (bgcolor, href, src). Пример:
Атака: filename.php?color=red” onload=”alert(‘The XSS!’)
Результат вставки позволяет выполнить onload в body. Требуется кодирование символа “. Общие рекомендации:
- Для значений атрибутов применяйте экранирование соответствующее контексту (HTML‑атрибут).
- Для URL в href/src используйте проверку схемы (https/http) или фильтр: разрешайте только допустимые схемы.
- Не допускайте javascript: в href. Проверяйте, что значение — допустимый абсолютный или относительный URL.
Пример проверки в псевдокоде:
function isSafeUrl(url) {
// Разрешаем только http, https и протоколозависимые относительные пути
return /^((https?:)|\/\/|\/)\/.test(url) || /^\//.test(url);
}
if (isSafeUrl(userHref)) {
link.href = userHref;
} else {
link.href = '/';
}Пример функции для защиты XSS на PHP
Ниже — пример минимального набора функций, которые показывают идеи: экранирование для атрибутов, проверка URL и безопасная вставка.
Примечание: для продакшена используйте filter_var($url, FILTER_VALIDATE_URL) и библиотеки для более строгой валидации.
Таблица приёмов и соответствующих функций (пример для PHP)
| Контекст вывода | Что кодировать | Рекомендация (PHP) | Комментарий |
|---|
| HTML — содержимое элемента | <, >, & | htmlspecialchars($str, ENT_QUOTES | ENT_HTML5) | Для текста внутри тега | | HTML — атрибуты | “, ‘ | htmlspecialchars($str, ENT_COMPAT) | Для значений атрибутов | | URL / href | схема/префикс | проверка регуляркой или filter_var | Заблокировать javascript: |
Эти примеры служат общей подсказкой; конкретные реализации зависят от языка и фреймворка.
Когда базовые меры не сработают (контрпримеры)
- Приложение динамически строит HTML в нескольких контекстах (атрибут, JS‑строка, CSS) и неправильно применяет одно экранирование для всех.
- Старые браузеры или нестандартные парсеры HTML могут интерпретировать данные иначе.
- Если вы используете внутренние функции, которые возвращают уже «отформатированный» HTML от стороннего модуля — данные всё ещё могут содержать опасный контент.
В таких случаях нужен многоступенчатый подход: контекстно‑зависимое экранирование + библиотека очистки + CSP.
Альтернативные подходы и инструменты
- Использовать шаблонизаторы, которые делают автоэкранирование по умолчанию (Twig, Handlebars, Razor и др.).
- Использовать DOMPurify или аналог для очистки пользовательского HTML.
- В фронтенде — избегать innerHTML, применять textContent и безопасные шаблоны.
- Ввести strict Content Security Policy (CSP) с запретом inline‑скриптов и подключением только доверённых источников.
Модель мышления (heuristic)
- Где данные могут попасть в браузер? URL, формы, API, заголовки, файлы.
- В каких контекстах данные выводятся? HTML, атрибут, JS‑строка, CSS, URL. Для каждого контекста — своё кодирование.
- Всегда минимизируйте «разрешённый» набор: если нужен только текст — не разрешайте теги.
Мини‑методология фикса XSS (для инцидента)
- Описание инъекции: откуда пришли данные, где отображаются.
- Воспроизведение: создать PoC в локальной среде.
- Временная защита: блокировать вход/выход (экранирование) и применить CSP.
- Исправление: скорректировать код, применить контекстное кодирование и модульные тесты.
- Развёртывание и мониторинг.
Чеклист ролей
Разработчик:
- Применил контекстное экранирование для каждого места вывода.
- Заменил innerHTML на textContent там, где вывод — текст.
- Добавил unit/integration тесты для примеров инъекций.
QA / Тестировщик:
- Прогнал негативные кейсы с типичными полезными нагрузками XSS.
- Проверил заголовки CSP и поведение при блокировке inline‑скриптов.
DevOps / SRE:
- Внёс CSP и другие HTTP‑безопасные заголовки на уровень сервера/ingress.
- Настроил мониторинг ошибок JavaScript и отчёты о нарушениях CSP.
Информационная безопасность:
- Провёл ручной и автоматизированный pentest, включая сканирование XSS.
- Дал рекомендации по библиотекам очистки и политике релизов.
Критерии приёмки
- Никакой пользовательский ввод не интерпретируется как HTML/JS без явной и безопасной очистки.
- Unit‑тесты покрывают основные PoC XSS (3–5 вариаций) и проходят в CI.
- CSP установлен хотя бы в режиме report‑only и не допускает inline‑скриптов.
- Логи/метрики фиксируют попытки инъекций и уведомляют команду.
Тестовые случаи / примеры тестов
- Передавать в поля: , “>
, javascript:alert(1). Ожидаемый результат: приложение не выполняет код.
- Проверить href с javascript: и data: — ожидаемая поведение: отвергнуть или заменить на безопасный URL.
Риски и смягчения
- Риск: потеря данных сессии и учётных записей через кражу cookies.
Смягчение: HttpOnly и Secure для cookies, SameSite. - Риск: обход CSP через JSONP/внешние библиотеки.
Смягчение: запретить ненужные источники и тщательно ревью внешних скриптов.
Примечания по приватности
Если вы сохраняете пользовательский ввод (комментарии, профили), подумайте о хранении только минимально необходимой информации. При обработке персональных данных соблюдайте требования локального законодательства о защите данных (например, GDPR/другие регуляции в вашей юрисдикции).
Короткая сводка для команды (SOP)
- Всегда валидируйте вход.
- Экранируйте контекстно (HTML, атрибут, JS, URL).
- Используйте проверенные библиотеки для очистки HTML.
- Внедрите CSP и безопасные заголовки.
- Покрывайте правки тестами и мониторьте попытки инъекций.
Глоссарий (в одну строку)
- XSS: внедрение и исполнение вредоносного скрипта в браузере пользователя;
- CSP: Content Security Policy — набор правил, ограничивающих источник исполняемого кода;
- innerHTML/textContent: методы DOM для вставки HTML или текста.
Итог
XSS остаётся распространённой и серьёзной угрозой, но её можно системно устранить, применяя контекстное экранирование, безопасные шаблонизаторы, проверенные библиотеки очистки и политики безопасности (CSP, заголовки). Команда должна иметь процессы для обнаружения, быстрого патча и тестирования фиксов.
Похожие материалы
Кастомные меню в Godot — старт, пауза, Game Over
Исправление BSoD btha2dp.sys — Bluetooth в Windows
Наложение производительности Windows 11 — как включить
Гостевой аккаунт в Windows 11 — как создать