sergeyv89
07.07.2026, 23:40
Введение
Если у вас есть сайт с формами, полями ввода или динамическим контентом, самый распространённый баг, от которого нужно держаться подальше, — XSS (Cross-Site Scripting). Это когда злоумышленник «вставляет» в вашу страницу вредоносный скрипт, который выполняется на стороне пользователя. Такое может привести к краже сессий, подделке действий или просто разному троллингу пользователей. Тут нет волшебных вариантов — нужно понимать, как работает атака и как её свести к нулю.
Что это такое
XSS — это тип уязвимости, связанный с тем, что сайт принимает и отображает ввод пользователя без должной обработки. Есть три основных типа:
- Reflected XSS — скрипт прилетает в URL или форму и сразу же выводится в ответе.
- Stored XSS — вредоносный код сохраняется в базе и показывается многим пользователям.
- DOM-based XSS — скрипт внедряется через манипуляции с DOM на стороне браузера.
Главная идея в том, что если вы вставляете пользовательские данные в HTML без фильтра и экранирования, вы рискуете.
Где применяется XSS
XSS можно встретить практически в любом месте, где есть ввод пользователя и последующее отображение или использование этих данных. Это может быть форма комментариев, поле поиска, страницы профиля, чаты, отзывы, или даже динамические ссылки и параметры URL. Если разработчики не думают о безопасности, то уязвимость может затаиться в самых неожиданых местах.
Как именно работают атаки XSS
Пример простого reflected XSS: пользователь вводит в строку поиска что-то вроде <script>alert(1)</script>, и этот код отдается обратно браузеру и выполняется. Хорошо, если это просто alert, но вместо него может быть что угодно — кража куки, подмена страницы, выполнение AJAX-запросов сессии от имени пользователя.
Stored XSS куда опаснее, потому что вредоносный код хранится у вас в базе и автоматически показывается многим пользователям. Например, в комментариях к статье может появиться скрипт, который передает куки злоумышленнику каждый раз, как кто-то читает комментарии.
DOM-based XSS — вариант, когда уязвимость проявляется не в ответе сервера, а на стороне браузера из-за плохой работы скриптов с динамическим контентом. Например, скрипт, который читает параметры из URL, вставляет их в страницу без фильтра и позволяет выполнить свой JavaScript.
Практические примеры уязвимостей
1) Допустим, у вас есть форма с поиском, и введенный текст вы выводите прямо в заголовок результата запросов, не экранируя. Пользователь вводит <script>…</script>, и этот код тут же начинается исполняться. Исправить — обязательно использовать функцию экранирования HTML-символов (например htmlspecialchars в PHP).
2) В комментариях к блогу вы сохраняете статью + комментарий в базу и потом показываете комментарии без фильтра. Тут сразу Stored XSS. Отфильтровывать надо либо на входе (например удалять все теги или разрешать только безопасный subset), либо экранировать при выводе.
3) На сайте есть скрипт, который читает GET параметр page и подставляет в DOM. Если вы забыли sanity-check, то через URL можно ввести вредоносный JS, который сработает на клиенте.
Чек-лист по защите
- Всегда фильтруйте и экранируйте пользовательские данные перед вставкой в HTML.
- Для HTML используйте функции, которые заменяют <, >, &, " на спецсимволы.
- Если вставляете данные в атрибуты, следите за кавычками и экранируйте.
- При выводе в JavaScript или JSON используйте специальные обработчики.
- Применяйте Content Security Policy (CSP) для ограничения выполнения скриптов и источников.
- Используйте HTTPOnly и Secure для куков, чтобы ограничить доступ через JS.
- Не доверяйте данным из внешних источников, проверяйте и валидируйте.
- Регулярно проводите аудит кода и сканируйте сайт на XSS с помощью инструментов.
- Для DOM-based XSS используйте безопасные методы вставки в DOM (например textContent вместо innerHTML).
- Обновляйте все библиотеки и фреймворки, которые используете.
Типичные ошибки новичков
- Вставка пользовательских данных прямо в HTML без экранирования.
- Попытка очистить данные удалением только тэгов script, не учитывая другие способы внедрения.
- Использование innerHTML вместо безопасных методов для обновления DOM.
- Отсутствие Content Security Policy, который мог бы блокировать исполнение внешних скриптов.
- Игнорирование XSS в динамическом контенте, например в URL-параметрах или JSON-ответах.
- Считают, что серверный фильтр достаточен и не проверяют клиентский код.
- Перенос опасных данных в cookie без правильных флагов безопасности.
- Не используют фреймворки с защитами по умолчанию, или не используют те возможности, что они предоставляют.
FAQ по XSS
В: Можно ли полностью защититься от XSS?
О: Да, если соблюдать все меры, особенно экранирование, CSP и проверку данных. Однако профилактика должна быть комплексной, ведь баги могут всплывать в самых разных местах.
В: Чем опасен Stored XSS по сравнению с Reflected?
О: Stored XSS — это как база террористов: вредный код сохраняется у вас в базе и затекает к большим массам пользователей автоматически, Reflected больше для одиночных атак.
В: Можно ли предотвратить XSS на стороне клиента?
О: Только частично. Основная защита должна быть на сервере, на клиенте дополняйте её безопасной работой с DOM и CSP.
В: Какие языки и фреймворки лучше всего помогают бороться с XSS?
О: Практически все современные фреймворки (React, Angular, Vue) имеют встроенные механизмы для защиты, если использовать их правильно. В PHP и Python есть функции для экранирования и фильтрации.
В: Что делать, если наш сайт рискованно зависит от пользовательского HTML?
О: Используйте белый список регулярных выражений или специализированные библиотеки для очистки и парсинга HTML, например DOMPurify или HTMLSanitizer.
В: Как проверить, что XSS у меня нет?
О: Используйте сканеры безопасности, например OWASP ZAP, Burp Suite, а также ручные тесты — попробуйте вводить в поля данные с тегами и спецсимволами и смотрите, не запускается ли скрипт.
Подводя итоги
XSS — это старый и хорошо изученный баг, и с ним бороться можно и нужно. Главное — никогда не вставлять пользовательские данные в страницу «как есть», а всегда фильтровать, экранировать и думать, где именно они оказываются. Если довести до автоматизма фильтрацию и применить превентивные меры вроде CSP, то всё почти гарантировано будет в порядке. Не стоит пересматривать методы защиты ежеминутно — лучше один раз правильно настроить всё, чем потом искать дырки. Ну а если вы только начинаете — совсем не стесняйтесь учиться и пробовать на своих тестовых стендах, так лучше понимаешь, как работает и где именно может быть проблема.
Если у вас есть сайт с формами, полями ввода или динамическим контентом, самый распространённый баг, от которого нужно держаться подальше, — XSS (Cross-Site Scripting). Это когда злоумышленник «вставляет» в вашу страницу вредоносный скрипт, который выполняется на стороне пользователя. Такое может привести к краже сессий, подделке действий или просто разному троллингу пользователей. Тут нет волшебных вариантов — нужно понимать, как работает атака и как её свести к нулю.
Что это такое
XSS — это тип уязвимости, связанный с тем, что сайт принимает и отображает ввод пользователя без должной обработки. Есть три основных типа:
- Reflected XSS — скрипт прилетает в URL или форму и сразу же выводится в ответе.
- Stored XSS — вредоносный код сохраняется в базе и показывается многим пользователям.
- DOM-based XSS — скрипт внедряется через манипуляции с DOM на стороне браузера.
Главная идея в том, что если вы вставляете пользовательские данные в HTML без фильтра и экранирования, вы рискуете.
Где применяется XSS
XSS можно встретить практически в любом месте, где есть ввод пользователя и последующее отображение или использование этих данных. Это может быть форма комментариев, поле поиска, страницы профиля, чаты, отзывы, или даже динамические ссылки и параметры URL. Если разработчики не думают о безопасности, то уязвимость может затаиться в самых неожиданых местах.
Как именно работают атаки XSS
Пример простого reflected XSS: пользователь вводит в строку поиска что-то вроде <script>alert(1)</script>, и этот код отдается обратно браузеру и выполняется. Хорошо, если это просто alert, но вместо него может быть что угодно — кража куки, подмена страницы, выполнение AJAX-запросов сессии от имени пользователя.
Stored XSS куда опаснее, потому что вредоносный код хранится у вас в базе и автоматически показывается многим пользователям. Например, в комментариях к статье может появиться скрипт, который передает куки злоумышленнику каждый раз, как кто-то читает комментарии.
DOM-based XSS — вариант, когда уязвимость проявляется не в ответе сервера, а на стороне браузера из-за плохой работы скриптов с динамическим контентом. Например, скрипт, который читает параметры из URL, вставляет их в страницу без фильтра и позволяет выполнить свой JavaScript.
Практические примеры уязвимостей
1) Допустим, у вас есть форма с поиском, и введенный текст вы выводите прямо в заголовок результата запросов, не экранируя. Пользователь вводит <script>…</script>, и этот код тут же начинается исполняться. Исправить — обязательно использовать функцию экранирования HTML-символов (например htmlspecialchars в PHP).
2) В комментариях к блогу вы сохраняете статью + комментарий в базу и потом показываете комментарии без фильтра. Тут сразу Stored XSS. Отфильтровывать надо либо на входе (например удалять все теги или разрешать только безопасный subset), либо экранировать при выводе.
3) На сайте есть скрипт, который читает GET параметр page и подставляет в DOM. Если вы забыли sanity-check, то через URL можно ввести вредоносный JS, который сработает на клиенте.
Чек-лист по защите
- Всегда фильтруйте и экранируйте пользовательские данные перед вставкой в HTML.
- Для HTML используйте функции, которые заменяют <, >, &, " на спецсимволы.
- Если вставляете данные в атрибуты, следите за кавычками и экранируйте.
- При выводе в JavaScript или JSON используйте специальные обработчики.
- Применяйте Content Security Policy (CSP) для ограничения выполнения скриптов и источников.
- Используйте HTTPOnly и Secure для куков, чтобы ограничить доступ через JS.
- Не доверяйте данным из внешних источников, проверяйте и валидируйте.
- Регулярно проводите аудит кода и сканируйте сайт на XSS с помощью инструментов.
- Для DOM-based XSS используйте безопасные методы вставки в DOM (например textContent вместо innerHTML).
- Обновляйте все библиотеки и фреймворки, которые используете.
Типичные ошибки новичков
- Вставка пользовательских данных прямо в HTML без экранирования.
- Попытка очистить данные удалением только тэгов script, не учитывая другие способы внедрения.
- Использование innerHTML вместо безопасных методов для обновления DOM.
- Отсутствие Content Security Policy, который мог бы блокировать исполнение внешних скриптов.
- Игнорирование XSS в динамическом контенте, например в URL-параметрах или JSON-ответах.
- Считают, что серверный фильтр достаточен и не проверяют клиентский код.
- Перенос опасных данных в cookie без правильных флагов безопасности.
- Не используют фреймворки с защитами по умолчанию, или не используют те возможности, что они предоставляют.
FAQ по XSS
В: Можно ли полностью защититься от XSS?
О: Да, если соблюдать все меры, особенно экранирование, CSP и проверку данных. Однако профилактика должна быть комплексной, ведь баги могут всплывать в самых разных местах.
В: Чем опасен Stored XSS по сравнению с Reflected?
О: Stored XSS — это как база террористов: вредный код сохраняется у вас в базе и затекает к большим массам пользователей автоматически, Reflected больше для одиночных атак.
В: Можно ли предотвратить XSS на стороне клиента?
О: Только частично. Основная защита должна быть на сервере, на клиенте дополняйте её безопасной работой с DOM и CSP.
В: Какие языки и фреймворки лучше всего помогают бороться с XSS?
О: Практически все современные фреймворки (React, Angular, Vue) имеют встроенные механизмы для защиты, если использовать их правильно. В PHP и Python есть функции для экранирования и фильтрации.
В: Что делать, если наш сайт рискованно зависит от пользовательского HTML?
О: Используйте белый список регулярных выражений или специализированные библиотеки для очистки и парсинга HTML, например DOMPurify или HTMLSanitizer.
В: Как проверить, что XSS у меня нет?
О: Используйте сканеры безопасности, например OWASP ZAP, Burp Suite, а также ручные тесты — попробуйте вводить в поля данные с тегами и спецсимволами и смотрите, не запускается ли скрипт.
Подводя итоги
XSS — это старый и хорошо изученный баг, и с ним бороться можно и нужно. Главное — никогда не вставлять пользовательские данные в страницу «как есть», а всегда фильтровать, экранировать и думать, где именно они оказываются. Если довести до автоматизма фильтрацию и применить превентивные меры вроде CSP, то всё почти гарантировано будет в порядке. Не стоит пересматривать методы защиты ежеминутно — лучше один раз правильно настроить всё, чем потом искать дырки. Ну а если вы только начинаете — совсем не стесняйтесь учиться и пробовать на своих тестовых стендах, так лучше понимаешь, как работает и где именно может быть проблема.