Защита от XSS в Node.js

Cross-site scripting (XSS) — это тип уязвимости, при котором атакующий внедряет вредоносные скрипты в веб‑страницы, исполняющиеся в браузере клиента. Такие скрипты могут выдавать себя за легитимный код страницы, похищать сессии, куки, изменять содержимое страницы или запускать действия от имени пользователя.
Важно: в 2021 году XSS занимал вторую позицию в списке самых опасных уязвимостей (Common Weakness Enumeration — Top 25). Если вы создаёте веб‑приложения, знание XSS и способов защиты — обязательное требование.
Что такое политика одного происхождения и как XSS её обходит
Политика одного происхождения (Same‑Origin Policy, SOP) ограничивает возможность одного происхождения (origin) читать или записывать данные другого. Браузеры применяют SOP для предотвращения кражи данных между сайтами.
XSS — это попытка обмануть браузер: внедрённый скрипт выглядит как часть целевой страницы, поэтому браузер исполняет его с правами той же origin. В результате атакующий может получить токены сессии, куки и другие защищённые данные.
Типы XSS:
- Reflected XSS — вредоносный ввод отправляется в запросе и немедленно отражается в ответе (часто в ссылках, параметрах GET/POST).
- Stored XSS — вредоносный код сохраняется на сервере (в базе данных, комментариях) и затем отдаётся многим пользователям.
- DOM‑based XSS — уязвимость в манипуляциях с DOM на стороне клиента (неправильная обработка location, innerHTML и т.п.).
Базовые меры защиты в Node.js
Ни одна мера не даёт 100% гарантии — применяйте комбинацию методов.
Санитизация и экранирование ввода
Санитизация (sanitization) — удаление или преобразование опасных символов. Экранирование (escaping) — преобразование символов в безопасные сущности при выводе (например, ‘<’ → ‘<’).
Разработчик обязан считать любой вход от пользователя — недоверенным. Если приложение принимает данные и потом отображает их в HTML, обязательно экранируйте их на выходе.
Пример с пакетом validator (как в исходном примере):
import validator from "validator";
let userInput = `Jane `;
let sanitizedInput = validator.escape(userInput);После выполнения получится:
Jane <script onload="alert('XSS hack');"></script>Важно: экранирование применяют при выводе в HTML. Санитизация на входе полезна, но не заменяет экранирование при выводе.
Ограничение формата вводимых данных
Проверяйте тип и формат данных: если поле должно содержать email — проверяйте его регулярным выражением или через валидатор. Для чисел используйте явное приведение и диапазоны. Чем более строгое правило, тем меньше поверхность атаки.
HTTP only cookie
Флаг httpOnly у cookie запрещает доступ из JavaScript (document.cookie). Установка флага уменьшает риск кражи сессионных куки через XSS.
Пример для Express (как в исходном тексте):
app.use(express.session({
secret: "secret",
cookie: {
httpOnly: true,
secure: true
}
})) Если cookie помечена httpOnly, попытка читать её через JavaScript вернёт пустую строку.
Content Security Policy (CSP)
CSP ограничивает источники, с которых можно загружать скрипты, стили, изображения и т.д. Правильно настроенная политика может нейтрализовать многие XSS‑атаки, запрещая inline‑скрипты и загрузку скриптов с внешних сайтов.
Пример простого заголовка CSP:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self';Примечание: CSP сложно полностью настроить для существующих приложений с большим количеством внешних скриптов — внедряйте постепенно.
Минимизируйте использование innerHTML и eval
Методы вроде element.innerHTML, document.write, eval, new Function — расширяют риск внедрения и исполнения непроверенного кода. По возможности используйте безопасные DOM‑API и шаблонизаторы, которые автоматически экранируют данные.
Защититесь на уровне шаблонизатора
Современные шаблонизаторы (Pug, EJS, Handlebars, React JSX) умеют автоматически экранировать переменные при вставке в HTML. Убедитесь, что вы не отключаете эту защиту (например, не используете «raw» вставки без нужды).
Когда базовые меры не сработают — типичные причины провалов
- Экранирование применяется не ко всем контекстам (HTML, атрибуты, URL, JavaScript внутри атрибутов). Каждый контекст требует отдельного подхода.
- Неправильная или неполная CSP (например, разрешён ‘unsafe-inline’).
- Хранение HTML, введённого пользователем, без чистки (stored XSS).
- DOM‑парсинг данных из location.hash/innerHTML без фильтрации (DOM XSS).
Практическая мини‑методология для команды разработки
- Принять правило: всё, что приходит от клиента — недоверенно.
- Валидировать формат на входе (чёткие схемы: Joi, Zod, Yup).
- На выходе — экранирование в зависимости от контекста (html, attr, url).
- Установить заголовки безопасности: CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy.
- Пометить cookie как httpOnly, secure и SameSite.
- Проводить автоматические сканирования и ручное тестирование (DAST, pentest).
Чек‑лист по ролям
Разработчик:
- Валидация и экранирование данных.
- Не использовать innerHTML без необходимости.
- Писать юнит‑тесты на ввод/вывод.
DevOps / Инфраструктура:
- Настройка заголовков безопасности на уровне прокси/серверов (Nginx, CDN).
- Обновление зависимостей и контроль сборок.
Команда безопасности:
- Регулярные DAST/pen‑test тесты.
- Code review фрагментов, работающих с HTML/JS.
Мини‑плейбук на случай инцидента XSS
- Идентификация: зафиксировать URL, payload, время и затронутых пользователей.
- Изоляция: при необходимости вывести сайт в режим ограниченного доступа.
- Устранение: удалить вредоносный контент, закрыть уязвимый эндпоинт или шаблон.
- Восстановление: откатить изменения, если уместно, и деплой исправления.
- Анализ: определить корневую причину и обновить тесты/процессы.
Критерии приёмки:
- Все входные данные проходят валидацию и экранирование.
- CSP настроена и не содержит ‘unsafe-inline’ в продакшене.
- Cookie имеют httpOnly и secure флаги.
- Автоматические тесты покрывают рефлекторные и хранимые сценарии XSS.
Дополнительные инструменты и альтернативные подходы
- Библиотеки для санитизации: DOMPurify (клиентская), sanitize-html (Node).
- Схемы валидации: Joi, Zod, Yup.
- Автоматические сканеры: OWASP ZAP, Burp Suite (DAST).
- CSP мониторинг: включать report‑uri/report‑to для тестирования политик до их ужёсточения.
Примеры кода и шаблоны
Проверка email с validator:
import validator from "validator";
if (!validator.isEmail(inputEmail)) {
throw new Error('Invalid email');
}Экран карты при выводе на шаблоне (Node + шаблонизатор или серверный рендеринг) — всегда использовать экранирование:
// Пример: в шаблонизаторе выводить как {{ userComment }} а не {{{ userComment }}}Безопасность и конфиденциальность (GDPR)
XSS может привести к утечке персональных данных. Если приложение обрабатывает персональные данные, добавьте в план реагирования уведомления и оценку воздействия. Убедитесь, что журналы инцидентов хранятся безопасно.
Итог и рекомендации
Важно применять многоуровневую стратегию: валидация на входе, экранирование при выводе, настройка заголовков безопасности и ограничение возможностей выполнения динамического HTML/JS. Регулярно тестируйте приложение сканерами и вручную — и обновляйте зависимости.
Факт‑бокс:
- XSS остаётся одной из наиболее распространённых и опасных веб‑уязвимостей.
- Защитные уровни: входная валидация → экранирование → CSP/заголовки → безопасные шаблонизаторы → мониторинг.
Важно: никакая отдельная мера не заменяет комплексного подхода.
Краткое резюме:
- Всегда рассматривайте ввод как недоверенный.
- Экранируйте данные при выводе в зависимости от контекста.
- Используйте httpOnly cookie, CSP и современные шаблонизаторы.
- Тестируйте и документируйте проверки.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone