Civil &: строительная инженерия
Как использовать JavaScript для обнаружения и предотвращения атак на межсайтовые скрипты (xss)
Table of Contents
Введение в межсайтовое скриптинг (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, который интегрируется с бэкэндом:
- Предоставление по запросу: Санитаризовать с использованием перед отправкой на сервер (но сервер все равно должен дезинфицировать).
- Сервер возвращает данные: Бэкэнд должен HTML-кодировать текст комментария.
- Клиентский рендеринг: Используйте или безопасный шаблонный движок. Никогда не используйте с необработанными пользовательскими данными.
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 Профилактический Читовый лист .