Гид по технологиям

Как предотвратить XSS: практическое руководство

7 min read Безопасность Обновлено 12 Apr 2026
Профилактика XSS: практическое руководство
Профилактика XSS: практическое руководство

Программист за ноутбуком, на экране код и окно браузера

Cross‑Site Scripting, широко известный как XSS, — один из самых опасных методов атак, используемых киберпреступниками. Разработчикам и специалистам по безопасности важно понимать, как работает XSS и какие практики блокируют атаки. XSS возникает, когда веб‑приложение показывает пользователю данные, не выполнив их корректную обработку с учётом контекста (HTML, JavaScript, атрибуты DOM).

Что такое XSS — кратко

XSS — это инъекция исполняемого кода (обычно JavaScript) в контент страницы, который затем выполняется в браузере других пользователей. Типы XSS по месту воздействия: отражённый (reflected), хранимый (stored), DOM‑основанный (DOM‑based). Короткое определение терминов:

  • Reflected: ввод из запроса сразу отражается в отклике.
  • Stored: вредоносный ввод сохраняется на сервере (например, в комментариях) и показывается многим пользователям.
  • DOM‑based: уязвимость появляется из‑за динамических операций с DOM на стороне клиента.

Важно: защита зависит от контекста, в котором вы выводите данные. Одна универсальная «волшебная» функции нет — нужно выбирать меры по месту использования.

Как предотвратить XSS через HTML

XSS позволяет злоумышленникам вставлять вредоносные скрипты в веб‑страницы. Пример: гость может оставить сообщение в гостевой книге, и если вы показываете сообщение без экранирования, код исполнится в браузере посетителя.

Предположим, что в поле сообщения злоумышленник вводит:

Если приложение напрямую выводит введённый текст как HTML, браузер выполнит этот скрипт. Чтобы этого не произошло, нужно кодировать специальные символы (<, >, &, \” и \’) перед вставкой в HTML. В контексте HTML (между тегами) используйте HTML‑энкодинг, например htmlspecialchars в PHP или соответствующие функции в других языках/фреймворках.

Советы:

  • Всегда эскейпьте пользовательский ввод при выводе в HTML.
  • Применяйте Content Security Policy (CSP) как дополнительный барьер (например, запрет inline‑скриптов).
  • Для вывода форматированного текста используйте безопасные библиотеки, которые удаляют опасные теги и атрибуты (whitelisting), а не просто удаляют теги полностью.

Как предотвратить XSS через JavaScript

Защита JavaScript‑кода от XSS

Логика HTML также применима к JavaScript. Часто данные из запроса вставляют в DOM с помощью innerHTML, вставки шаблонных строк или document.write — и это даёт атаке возможность выполнить код.

Рассмотрим пример из исходного текста (код сохранён для точности):

Если параметр search содержит пользовательский ввод, и вы используете innerHTML, то атакующий может завершить строку и добавить собственный JavaScript:

filename.php?search=a" alert("The XSS!"); f= "

Результат в коде будет исполнен браузером и атака успешна. Чтобы это предотвратить:

  • Не используйте innerHTML для вывода непроверенных данных. Вместо этого применяйте textContent или setAttribute для безопасного вставления текста.
  • Эскейпьте кавычки и символы меньше/больше, если данные вставляются в JavaScript‑строку или в HTML‑атрибут.
  • Преобразовывайте данные в безопасный формат при интерполяции в шаблонах.

Примеры безопасных приёмов:

  • element.textContent = userInput;
  • element.setAttribute(‘data-value’, safeValue);

Как предотвратить DOM‑основанный XSS

DOM‑XSS появляется, когда JavaScript на клиенте обрабатывает данные (например, из location.hash, search или данных формы) и изменяет DOM напрямую без валидации/эскейпинга.

Пример уязвимого кода (как в исходном материале):

"/>

Атакующий может передать:

filename.php?color=red" onload="alert('The XSS!')

И браузер получит:

Чтобы защититься:

  • Для атрибутов проверяйте формат (например, допустимые значения цвета, URL и т. п.).
  • Эскейпьте кавычки в атрибутах (encodeAttributeValue).
  • Ограничьте значения enum‑списками допустимых опций.
  • В случаях, когда вы ожидаете URL, проверяйте схему (http/https) и не допускайте javascript: в href.

Обратите внимание на пример javascript:href:

Проверяйте и нормализуйте URL перед вставкой в href: допускайте только безопасные схемы (http, https, mailto и т. п.), и используйте относительные пути с осторожностью.

Пример функции защиты XSS на PHP

Защитите сайт от XSS с помощью PHP‑кода

В исходном материале приведена таблица с советами и примером на PHP. Перевод таблицы и пояснения:

Контекст выводаРекомендуемая функция/шаблон
Вставка в HTML‑атрибутhtmlspecialchars($str, ENT_COMPAT) — кодирует двойные кавычки
Вставка в JavaScript/атрибут DOMhtmlspecialchars($str, ENT_NOQUOTES) — не кодирует кавычки, применяйте с осторожностью и только если знаете контекст

| Проверка URL | ‘/^(((https?)|(\/\/))).*/‘ — простая проверка схемы (пример) |

Пример кода из исходника (с сохранением оригинального блока):

Примечания по коду:

  • real_url(data) в примере выглядит как псевдо‑функция — в реальном приложении используйте собственную валидацию/нормализацию URL.
  • ENT_COMPAT кодирует двойную кавычку, ENT_NOQUOTES и ENT_QUOTES используются в зависимости от контекста.

Практическая методология защиты (мини‑метод)

  1. Идентифицируйте контексты вывода (HTML тело, атрибуты, JavaScript, CSS, URL).
  2. Для каждого контекста примените соответствующую функцию кодирования/эскейпинга.
  3. Входные данные валидируйте по белому списку (формат, длина, enum).
  4. По возможности избегайте вставки пользовательского ввода как HTML — используйте textContent/innerText.
  5. Настройте CSP, чтобы ограничить загрузку внешних скриптов и запретить inline‑скрипты.
  6. Регулярно тестируйте приложение с помощью автоматизированных сканеров и ручного тестирования (пентестов).

Чеклист для разработчика и команды безопасности

Разработчик:

  • Использовать textContent вместо innerHTML для вывода текста.
  • Эскейпить данные перед вставкой в HTML/атрибуты/JS/CSS.
  • Проверять схемы URL при приёме ссылок.
  • Ограничивать набор допустимых значений для полей (enum, regex).

Тестировщик/пентестер:

  • Проверить отражённый, хранимый и DOM‑XSS для всех точек ввода.
  • Попробовать payload‑ы с кавычками, закрывающими тег, и вложенными тегами.
  • Проверить настройки CSP и недопустимые источники скриптов.

Администратор/DevOps:

  • Включить и поддерживать CSP, SRI, безопасные заголовки (X‑Content‑Type‑Options, X‑Frame‑Options).
  • Обеспечить обновление библиотек и фреймворков.

Критерии приёмки (Acceptance)

Чтобы фича считалась защищённой от XSS:

  • Никто из тестировщиков не может выполнить JavaScript из пользовательского ввода в любых целевых контекстах.
  • Все поля проходят валидацию и/или безопасный эскейпинг при выводе.
  • CSP настроен и не допускает inline‑скрипты без nonce/hashes (если возможно).
  • Автотесты покрывают основные кейсы эскейпинга.

Плейбук реагирования и SOP — при обнаружении XSS

  1. Изолировать уязвимую функциональность (при возможности выключить/скрыть поле).
  2. Восстановить безопасное значение (удалить вредоносный контент из хранилища).
  3. Провести срочный код‑ревью и патч: корректный эскейпинг/проверка входа.
  4. Развернуть патч и выполнить регрессионные тесты.
  5. Проанализировать логи на предмет эксплойта (какие учётные записи/временные метки).
  6. Уведомить пользователей и, если требуется по политике, регуляторов.

Важно: документировать все шаги и сохранять копии уязвимых данных для последующего анализа.

Тестовые случаи / критерии приёмки

  1. Вводить в поля: , “>”, ‘);alert(1);// — ожидать, что код нигде не исполняется.
  2. Передача в параметре URL специальных последовательностей — проверять, что итоговый DOM безопасен.
  3. Проверка CSP: попытки inline‑выполнения блокируются.
  4. Проверка href: javascript: схемы отвергаются.

Mental models и эвристики

  • Контекст важнее входа: одно и то же значение безопасно в текстовом контексте и опасно внутри атрибута.
  • «Эскейпинг зависит от выхода»: выбирайте метод кодирования по месту вставки.
  • Принцип наименьших привилегий: разрешайте только то, что нужно (white‑list).

Security hardening — дополнительные меры

  • Content Security Policy (CSP): запрет inline‑script и подключений с небезопасных доменов.
  • HTTP‑Only и Secure для cookies.
  • Использование современных фреймворков, которые по умолчанию экранируют шаблоны (например, React, Vue по умолчанию защищают от простого XSS при использовании безопасных практик).
  • Минификация и подпись внешних скриптов (Subresource Integrity — SRI).

Пример потока принятия решения (Mermaid)

flowchart TD
  A[Начало: пользовательский ввод] --> B{Куда вставляется значение?}
  B -->|Текст внутри элемента| C[Использовать textContent]
  B -->|HTML/innerHTML| D[Эскейпить символы <,>,&,',']
  B -->|Атрибут| E[Эскейпить кавычки, проверять enum/формат]
  B -->|JavaScript строка| F[Экранировать кавычки, не использовать eval]
  B -->|href/src| G[Проверить схему 'http/https/ftp' и нормализовать]
  C --> Z[Готово]
  D --> Z
  E --> Z
  F --> Z
  G --> Z

Короткий словарь

  • XSS — Cross‑Site Scripting, инъекция исполняемого кода в контент страницы.
  • CSP — Content Security Policy, заголовок для ограничения ресурсов.
  • Эскейпинг — замена специальных символов на безопасные HTML‑сущности.

Когда предложенные методы могут не сработать (контр‑примеры)

  • Если приложение ошибочно выполняет пользовательский ввод через eval или new Function, эскейпинг может быть проигнорирован.
  • Если сторонняя библиотека манипулирует DOM небезопасно, даже корректный бекенд не спасёт.
  • CSP можно обойти, если разрешены небезопасные источники или включены inline‑скрипты с nonce‑/hash‑неправильной конфигурацией.

Примеры альтернатив и дополнений

  • Использовать строгие шаблонизаторы, которые применяют токенизацию и автоматический эскейпинг.
  • Применять библиотечные санитайзеры (DOMPurify) для случаев, когда нужно разрешить ограничённое форматирование HTML.

Заключение

XSS остаётся одной из самых распространённых и при этом предотвратимых уязвимостей веб‑приложений. Ключи к надёжной защите: понимать контекст вывода, использовать подходящий эскейпинг, валидировать ввод по белому списку и вводить дополнительные барьеры (CSP, SRI, secure headers). Командная ответственность — от разработчиков до DevOps и тестировщиков — снижает риск успешной атаки.

FAQ

Q: Достаточно ли использовать только htmlspecialchars в PHP?

A: Нет. htmlspecialchars защищает при вставке в HTML‑контент, но для других контекстов (JavaScript, CSS, URL, атрибуты) нужны свои методы. Всегда выбирать эскейпинг в зависимости от целевого контекста.

Q: Можно ли полагаться только на Content Security Policy?

A: CSP — мощный дополнительный уровень защиты, но не заменяет корректную обработку входных данных. CSP помогает смягчить последствия, но не устраняет уязвимую логику на сервере или в клиентском коде.

Q: Что безопаснее для вставки текста — textContent или innerHTML?

A: textContent безопаснее, так как вставляет текст без интерпретации HTML. innerHTML интерпретирует HTML и опасен для непроверенных данных.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как пережить долгий процесс собеседований
Карьера

Как пережить долгий процесс собеседований

Как понять, что пора сменить карьеру
Карьера

Как понять, что пора сменить карьеру

Как стать VR‑разработчиком
Карьера VR

Как стать VR‑разработчиком

GitHub Desktop на Windows — руководство
Разработка

GitHub Desktop на Windows — руководство

Как получить IT‑работу без технического диплома
Карьера

Как получить IT‑работу без технического диплома

Как стать фактчекером — шаги и чек-листы
Журналистика

Как стать фактчекером — шаги и чек-листы