Введение в межсайтовое скриптинг (XSS) и JavaScript защиты

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

Понимание трех типов XSS

Прежде чем погрузиться в профилактику, важно понять три основные категории XSS: сохраненный, отраженный и основанный на DOM. Каждый из них требует немного другого подхода к обнаружению и профилактике.

Хранится XSS

Хранимая (постоянная) XSS происходит, когда вредоносный ввод постоянно хранится на сервере (например, в базе данных, сообщении на форуме или комментарии) и позже обслуживается пользователям без надлежащей санации.

Отраженный XSS

Отраженный XSS происходит, когда вредоносный скрипт отражается от веб-сервера, как правило, через параметр URL или форму представления. Злоумышленник обманывает жертву, нажимая на созданную ссылку, и введенный код выполняется немедленно. В отличие от сохраненного XSS, полезная нагрузка не сохраняется.

Dom-Based XSS

XSS на основе DOM является чисто клиентской уязвимостью. Полезная нагрузка атаки изменяет среду DOM в браузере жертвы. Вредоносный код никогда не касается сервера; он исходит из клиентской стороны JavaScript, который небезопасно обрабатывает пользовательский ввод (например, чтение из , или ).

Обнаружение атак XSS с помощью JavaScript

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

Вводная валидация и санизация

Всегда проверяйте и дезинфицируйте пользовательские вводы на стороне клиента перед обработкой. Используйте вместо , чтобы предотвратить выполнение сценария. Следующая функция удаляет опасные символы из строки:

function sanitizeInput(input) {
 const div = document.createElement('div');
 div.textContent = input;
 return div.innerHTML;
}

Это работает, потому что настройка не интерпретирует HTML-теги; она рассматривает все как простой текст. содержит ускользающие версии любых специальных символов HTML (например, , , ).

Мониторинг DOM-мутаций для подозрительных элементов

Злоумышленники часто вводят теги или обработчики событий , ] в DOM. Используя API , вы можете наблюдать за неожиданными вставками элементов.

const observer = new MutationObserver((mutations) => {
 mutations.forEach((mutation) => {
 mutation.addedNodes.forEach((node) => {
 if (node.nodeType === 1) { // element node
 if (node.tagName === 'SCRIPT') {
 console.warn('Potential XSS: a script element was injected via DOM.');
 node.remove(); // or log and analyze
 }
 // Check for dangerous attributes
 if (node.hasAttribute('onerror') || node.hasAttribute('onload')) {
 console.warn('Suspicious event handler attribute detected.');
 }
 }
 });
 });
});
observer.observe(document.body, { childList: true, subtree: true });

Осторожность: Блокировка скриптов через может быть обойдена умными злоумышленниками и может нарушить законную функциональность. Используйте это как инструмент мониторинга, а не как основной механизм предотвращения.

Проверка URL и параметров хэша

Для XSS на основе DOM безопасно считывайте компоненты URL с помощью и избегайте прямого вставки значений в HTML.

const params = new URLSearchParams(window.location.search);
const userParam = params.get('name');
if (userParam && /[<>"'\/]/.test(userParam)) {
 console.warn('Potential XSS in parameter: ' + userParam);
 // Do not use this value in the DOM without encoding
}

Предотвращение атак XSS с помощью JavaScript

Для предотвращения требуется многоуровневый подход. JavaScript сам по себе не может полностью защитить приложение, но в сочетании с надлежащей санитаризацией бэкэнда и политикой безопасности контента (CSP) он значительно снижает риск.

Закодируйте все данные, контролируемые пользователем, прежде чем вводить их в DOM

Золотое правило: никогда не вставляйте ненадежные данные непосредственно в DOM. Используйте безопасные методы DOM вместо внутреннего HTML.

[[[ФЛТ:19]] или [[ФЛТ:20]]

const userInput = getUserInput();
const safeText = document.createTextNode(userInput);
document.getElementById('output').appendChild(safeText);

Когда вы должны использовать , санируйте с библиотекой

Если вам абсолютно необходимо визуализировать HTML (например, из богатого текстового редактора), полагайтесь на доверенную библиотеку санитарии, такую как DOMPurify. DOMPurify - это широко используемая, проверенная в бою библиотека, которая удаляет вредоносный код при сохранении безопасного HTML.

// Example with DOMPurify (install via npm or CDN)
const dirty = '<img src=x onerror="alert(1)">';
const clean = DOMPurify.sanitize(dirty);
document.getElementById('content').innerHTML = clean;

DOMPurify работает путем разбора входных данных, удаления опасных тегов и атрибутов и возврата только разрешенных элементов. Просмотр DOMPurify на GitHub.

Избегайте опасных функций JavaScript

Некоторые методы и свойства JavaScript известны тем, что позволяют использовать XSS. Избегайте или строго контролируйте:

  • — используйте или правильно продезинфицируйте.
  • , — то же правило.
  • — никогда не используйте с пользовательским вводом.
  • — может быть использован, если какой-либо вход сцеплен.
  • / со струнным кодом — избегайте; используйте вместо этого ссылки на функции.
  • Конструктор — аналогично .

Внедрить политику безопасности контента (CSP) через JavaScript?

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

const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = "default-src 'self'; script-src 'self' 'unsafe-inline'"; // Be very careful with 'unsafe-inline'
document.head.appendChild(meta);

Для производства настройте CSP на своем веб-сервере или обратном прокси. Документация MDN CSP предоставляет исчерпывающее руководство.

Дополнительные меры безопасности

Помимо тактики, характерной для JavaScript, стратегия предотвращения XSS включает в себя следующие важные меры:

  • Всегда проверяйте на стороне сервера. Проверка на стороне клиента может быть обойдена. Никогда не доверяйте данным клиента.
  • Используйте соответствующие заголовки HTTP-ответов. , и особенно .
  • Вывод кодирует каждый раз, когда вы предоставляете пользовательские данные. Контекст имеет значение: кодирование для объектов HTML, кодирование URL, кодирование строк JavaScript и т. д.
  • Поддерживайте обновления зависимостей. Уязвимые библиотеки JavaScript (например, более старые версии jQuery) являются общим вектором XSS. Используйте npm-аудит или аналогичные инструменты.
  • Используйте фреймворки со встроенной защитой XSS. Реагируйте, угловатые и Vue автоматически выходят из вывода по умолчанию. или
  • Внедряйте строгий CSP. Избегайте и , если это возможно. Используйте нонс или хэши для встроенных сценариев.

Пример из реального мира: безопасное рендеринг комментариев

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

  1. Предоставление по запросу: Санитаризовать с использованием перед отправкой на сервер (но сервер все равно должен дезинфицировать).
  2. Сервер возвращает данные: Бэкэнд должен HTML-кодировать текст комментария.
  3. Клиентский рендеринг: Используйте или безопасный шаблонный движок. Никогда не используйте с необработанными пользовательскими данными.
function renderComment(comment) {
 const item = document.createElement('div');
 item.className = 'comment';
 const body = document.createElement('p');
 body.textContent = comment.body; // escaped by browser
 item.appendChild(body);
 document.getElementById('comments').appendChild(item);
}

Проверка вашей обороны

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

Используйте инструменты разработчика браузера для проверки DOM и обеспечения того, чтобы полезные нагрузки ускользали. Также проверьте соблюдение CSP, проверив консоль на наличие сообщений о нарушениях.

Заключение

Межсайтовые скриптинги остаются серьезной угрозой, но JavaScript предлагает мощные инструменты для обнаружения и предотвращения. Проверяя вводы, отслеживая изменения DOM, избегая вывода и интегрируясь с надежными библиотеками, такими как DOMPurify, вы можете значительно укрепить безопасность на стороне клиента. Помните, что меры на стороне клиента не являются серебряной пулей; они дополняют стратегию защиты на стороне сервера, заголовки CSP и регулярные аудиты безопасности. Будьте бдительны, часто тестируйте и обновляйте свои библиотеки.

Для дальнейшего чтения, обратитесь к OWASP XSS страница и OWASP XSS Профилактический Читовый лист .