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

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

6 min read Безопасность Обновлено 11 Dec 2025
Защита от XSS в Node.js
Защита от XSS в Node.js

крупный план клавиатуры с надписью HTTP

Кросс-сайтовый скриптинг (XSS) — это класс уязвимостей, при котором атакующий внедряет вредоносный код (обычно JavaScript) в контент, который затем отображается доверенным пользователям. В результате злоумышленник может украсть сессионные токены, подменять содержимое страницы, выполнять действия от имени пользователя или перенаправлять на фишинговые страницы.

Важно: браузеры опираются на политику одного происхождения (Same-Origin Policy, SOP), но XSS эксплуатирует то, что браузер не всегда способен отличить легитимный HTML/JS от вредоносного.

Факты: XSS стабильно входит в топ уязвимостей и в 2021 году занимал второе место в списке CWE Top 25 по опасности.

Как XSS работает — кратко

  • SOP (Same-Origin Policy) ограничивает доступ между разными доменами. XSS обходит защиту, заставляя браузер выполнить вредоносный код в контексте доверенного сайта.
  • Атакующий вставляет скрипт в поля ввода, комментарии, URL-параметры или в базу данных (если приложение выводит данные без экранирования).
  • При загрузке страницы браузер выполняет скрипт и код получает доступ к DOM, кукам (если не защищены), localStorage и т.д.

Типы XSS:

  • Reflected XSS — вредоносный код возвращается в ответе и выполняется сразу при переходе по ссылке.
  • Stored XSS — код сохраняется на сервере (в базе данных) и выполняется при просмотре контента другими пользователями.
  • DOM-based XSS — уязвимость на стороне клиента: манипуляция DOM ведёт к выполнению вредоносного кода.

Основные принципы защиты (в одном предложении каждый)

  • Очищайте и валидируйте любой ввод — никогда не доверяйте данным от клиента.
  • Кодируйте (escape) все данные перед вставкой в HTML, атрибуты, JavaScript и в URL.
  • Применяйте безопасные заголовки: Content-Security-Policy, X-Content-Type-Options, Referrer-Policy и др.
  • Ограничьте доступ к кукам через HttpOnly, Secure и SameSite.
  • Используйте проверенные шаблонизаторы и библиотеки для экранирования вывода.

Ниже — системное руководство для разработчиков и инженеров, с примерами кода, рекомендациями по библиотекам и тестами.

1. Санитизация и валидация ввода

Атакующему нужно доставить вредоносные данные в ваше приложение и заставить сервер/клиент отобразить их. Поэтому первая защита — очищать и валидировать входящие данные.

  • Используйте whitelisting (разрешённые форматы) вместо blacklist. Если поле должно быть email — принимайте только email.
  • Для простых проверок удобно использовать validator и подобные библиотеки.

Пример: экранирование HTML с помощью validator.escape:

import validator from "validator";

let userInput = "Jane ";
let sanitizedInput = validator.escape(userInput);
console.log(sanitizedInput);
// Вывод: Jane <script onload="alert('XSS hack');"></script>

Дополнительно: для контента HTML, который нужно сохранить (например, WYSIWYG), используйте библиотеки типа DOMPurify (на стороне клиента) или sanitize-html (на сервере) с явно настроенными разрешёнными тегами и атрибутами.

2. Кодирование вывода (Output Encoding)

Всегда кодируйте данные перед вставкой в контекст:

  • Внутри HTML — HTML-экранирование.
  • В атрибутах — дополнительное экранирование кавычек и т.д.
  • В JavaScript-литералах — экранирование специальных символов.
  • В URL — encodeURIComponent.

Хорошие шаблонизаторы (Pug, EJS с авто-экранированием или React на сервере) по умолчанию экранируют вывод. Не отключайте авто-экранирование без веской причины.

3. Защита по заголовкам и CSP

Content Security Policy (CSP) ограничивает, откуда можно загружать скрипты, стили и другие ресурсы. CSP существенно снижает риск XSS, особенно для reflected и stored XSS.

Пример настроек через helmet:

import express from "express";
import helmet from "helmet";

const app = express();
app.use(helmet());
// Дополнительно настраиваем CSP
app.use(
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "https://trustedscripts.example.com"],
      objectSrc: ["'none'"],
      upgradeInsecureRequests: [],
    },
  })
);

CSP — мощный инструмент, но требует тестирования (в строгом режиме может ломать легитимный функционал).

4. HTTP-only, Secure и SameSite куки

Куки с флагом HttpOnly недоступны через JavaScript — это защищает сессионные идентификаторы от кражи через XSS.

Пример установки куки через express-session:

app.use(session({
  secret: "секретная_фраза",
  cookie: {
    httpOnly: true,
    secure: true,      // требует HTTPS
    sameSite: "lax",  // или 'strict' в зависимости от UX
  },
}));

Важно: secure требует HTTPS в проде. sameSite помогает снизить риск CSRF.

5. Используйте безопасные шаблонизаторы и избегайте unsafe-eval

  • Не вставляйте сырые строки HTML через innerHTML без предварительной очистки.
  • Избегайте eval, new Function и похожих конструкций.
  • На фронте применяйте DOMPurify для контента, генерируемого пользователем.

6. Логика на стороне сервера и принцип наименьших привилегий

  • Не храните или не логируйте секреты в открытом виде.
  • Ограничьте доступ к административным интерфейсам.
  • Проводите ревью изменений, которые меняют вывод HTML/JS.
  • CSP + Subresource Integrity (SRI) для внешних скриптов.
  • Content Security Policy в режиме отчёта (report-only) для тестирования.
  • Web Application Firewall (WAF) как дополнительный уровень защиты (не заменяет корректную разработку).
  • Автоматизированные сканеры безопасности и SAST/DAST в CI.

Важно: никакой один механизм не даёт 100% гарантии — защита должна быть многослойной.

Критерии приёмки (минимум):

  • Все пользовательские поля проходят валидацию и/или санитизацию.
  • Шаблонизатор экранирует вывод по умолчанию или ручной вывод помечен и проверен.
  • Наличие CSP в предельной/тихо-отчётной конфигурации и план тестирования.
  • Куки сессии имеют httpOnly и secure в продовой среде.
  • Unit/Integration тесты покрывают сценарии XSS и автоматические тесты в CI.

Минимальные тест-кейсы:

  • Попытаться вставить в форму и убедиться, что при отображении страница не выполняет alert.
  • Попытаться внедрить событие в атрибут, например: “ onerror=… “, и проверить, что атрибуты экранируются.
  • Тест CSP: попытаться загрузить скрипт с другого домена и убедиться, что блокируется.

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

  • Очищает ввод по контракту API.
  • Не использует innerHTML без очистки.
  • Добавляет тесты на XSS.

DevOps / SRE:

  • Настроил HTTPS, HSTS и secure cookies.
  • Включил заголовки безопасности (helmet).
  • Развернул CSP и мониторинг нарушений.

Тестировщик:

  • Выполняет ручные и автоматические XSS-тесты.
  • Проверяет политику CSP и отчёты.

Команда безопасности:

  • Проводит периодическую проверку зависимостей.
  • Настраивает SAST/DAST и triage уязвимостей.
  1. Изолировать источник: временно отключить функционал, принимающий ввод (если возможно).
  2. Заблокировать подозрительные аккаунты/IP и сохранить логи (с учётом GDPR).
  3. Провести форензику: какие записи вывели вредоносный код, кто пострадал, какие данные могли быть скомпрометированы.
  4. Внедрить патч: санитизация/экранирование/исправление шаблонов.
  5. Развернуть фиксы в тестовом окружении, затем в проде через проверенный процесс CI/CD.
  6. Уведомить пострадавших, если были утечки персональных данных (учитывать требования законодательства).
  7. Провести ретроспективу и обновить SOP.
  • Высокий риск: Stored XSS в публичных комментариях — mitigation: строгая санитизация + CSP + модерация.
  • Средний риск: Reflected XSS в поиске — mitigation: кодирование вывода + автоматические тесты.
  • Низкий риск: DOM XSS в вспомогательных скриптах — mitigation: избегать unsafe DOM-операций, DOMPurify.
  • XSS: внедрение и исполнение вредоносного скрипта в контексте доверённого сайта.
  • CSP: механизм браузера, ограничивающий источники ресурсов.
  • HttpOnly: флаг куки, запрещающий доступ через JavaScript.
  • DOMPurify / sanitize-html: библиотеки для безопасной очистки HTML.
  • CSP в строгом режиме может блокировать сторонние виджеты (аналитика, чат). Решение: постепенное внедрение в report-only и whitelist доверенных источников.
  • Сильная валидация может отвергать допустимые пользовательские данные (WYSIWYG) — в этом случае применять контекстную санитизацию с явным списком разрешённых тегов.
  • XSS — обычная, но решаемая проблема: комбинируйте валидацию, кодирование вывода, заголовки безопасности и проверенные библиотеки.
  • Тестируйте и автоматизируйте проверки в CI, поддерживайте процесс реагирования на инциденты.
  • Документируйте решения и обязанности для каждой роли: разработчик, SRE, тестировщик, безопасность.

Дополнительные материалы: начните с обзора CSP, изучите DOMPurify и sanitize-html, включите helmet в middleware Express.

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

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

Как собрать Mini-ITX ПК — пошаговое руководство
Hardware

Как собрать Mini-ITX ПК — пошаговое руководство

sar: анализ производительности Linux (sysstat)
Linux

sar: анализ производительности Linux (sysstat)

Сохранить скриншот в PDF на Windows 10
Руководство

Сохранить скриншот в PDF на Windows 10

Изменить или удалить пароль книги Excel
Excel

Изменить или удалить пароль книги Excel

Как находить скидки и бесплатные приложения для Android
Мобильные приложения

Как находить скидки и бесплатные приложения для Android

Читы и функции RetroArch: руководство
Ретро игры

Читы и функции RetroArch: руководство