Найдите уязвимость и предложите меры защиты в следующем шаблоне на фронтенде: element.innerHTML = userInput; — как превратить потенциальную XSS‑уязвимость в безопасную обработку данных и какие дополнения (CSP, кодирование вывода) применить
Проблема - Прямое присвоение: `element.innerHTML = userInput;` — интерпретирует вход как HTML/JS, поэтому любой пользовательский ввод может внедрить скрипт (XSS): теги ``, атрибуты-обработчики (`onclick`), `javascript:`-URI, SVG/CDATA и т.д. Рекомендации (по приоритету) 1) Если нужен только текст — не вламывайся в HTML - Используй textContent: element.textContent = userInput; 2) Если нужно позволить часть HTML — обязательно санитизация (whitelist) - Библиотека (рекомендуется): DOMPurify const clean = DOMPurify.sanitize(userInput); element.innerHTML = clean; - Настройте политики (разрешённые теги/атрибуты), удаляйте event-атрибуты и inline-стили, отключайте `ALLOW_UNKNOWN_PROTOCOLS` для защиты от `javascript:`. 3) Выходное кодирование по контексту - Для вставки в HTML-текст: экранировать `& " ' /` function escapeHTML(s){return s .replace(/&/g,'&').replace(/</g,'<') .replace(/>/g,'>').replace(/"/g,'"') .replace(/'/g,''');} - Для атрибутов/URL/JS/CSS — специальные схемы кодирования. Не используйте общее экранирование вместо контекстного. 4) Content Security Policy (CSP) - Настройте CSP, чтобы ограничить выполнение нежелательных скриптов и ресурсов. Пример заголовка: Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; style-src 'self' 'nonce-'; report-to / csp-report-endpoint - Не используйте `unsafe-inline` и `unsafe-eval`. Для легитимных inline-скриптов используйте nonce или hashes. 5) Trusted Types (защита от innerHTML) - Включите Trusted Types в браузерах и создайте политику, которая только через проверенный санитайзер позволит HTML: window.trustedTypes.createPolicy('default', { createHTML: (s) => DOMPurify.sanitize(s) }); element.innerHTML = trustedTypes.defaultPolicy.createHTML(userInput); 6) Дополнительные меры - Валидируйте и ограничивайте ввод на сервере (длина, допустимые символы). - HttpOnly, Secure, SameSite для куки. - Subresource Integrity (SRI) для внешних скриптов. - Логи и отчёты CSP (report-uri/report-to). - Обновляйте библиотеки и проверяйте зависимости. Короткие примеры - Простой безопасный вывод текста: element.textContent = userInput; - Санитизация с DOMPurify перед вставкой HTML: const clean = DOMPurify.sanitize(userInput, {ALLOWED_TAGS: ['b','i','a'], ALLOWED_ATTR: ['href']}); element.innerHTML = clean; - Trusted Types + DOMPurify: window.trustedTypes.createPolicy('default', {createHTML: (s)=>DOMPurify.sanitize(s)}); element.innerHTML = trustedTypes.defaultPolicy.createHTML(userInput); Итого: не присваивайте необработанный ввод в innerHTML. Либо используйте textContent, либо валидный санитайзер + контекстное кодирование, дополните строгой CSP и (по возможности) Trusted Types. Это значительно снизит риск XSS.
- Прямое присвоение: `element.innerHTML = userInput;` — интерпретирует вход как HTML/JS, поэтому любой пользовательский ввод может внедрить скрипт (XSS): теги ``, атрибуты-обработчики (`onclick`), `javascript:`-URI, SVG/CDATA и т.д.
Рекомендации (по приоритету)
1) Если нужен только текст — не вламывайся в HTML
- Используй textContent:
element.textContent = userInput;
2) Если нужно позволить часть HTML — обязательно санитизация (whitelist)
- Библиотека (рекомендуется): DOMPurify
const clean = DOMPurify.sanitize(userInput);
element.innerHTML = clean;
- Настройте политики (разрешённые теги/атрибуты), удаляйте event-атрибуты и inline-стили, отключайте `ALLOW_UNKNOWN_PROTOCOLS` для защиты от `javascript:`.
3) Выходное кодирование по контексту
- Для вставки в HTML-текст: экранировать `& " ' /`
function escapeHTML(s){return s
.replace(/&/g,'&').replace(/</g,'<')
.replace(/>/g,'>').replace(/"/g,'"')
.replace(/'/g,''');}
- Для атрибутов/URL/JS/CSS — специальные схемы кодирования. Не используйте общее экранирование вместо контекстного.
4) Content Security Policy (CSP)
- Настройте CSP, чтобы ограничить выполнение нежелательных скриптов и ресурсов. Пример заголовка:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; style-src 'self' 'nonce-'; report-to / csp-report-endpoint
- Не используйте `unsafe-inline` и `unsafe-eval`. Для легитимных inline-скриптов используйте nonce или hashes.
5) Trusted Types (защита от innerHTML)
- Включите Trusted Types в браузерах и создайте политику, которая только через проверенный санитайзер позволит HTML:
window.trustedTypes.createPolicy('default', {
createHTML: (s) => DOMPurify.sanitize(s)
});
element.innerHTML = trustedTypes.defaultPolicy.createHTML(userInput);
6) Дополнительные меры
- Валидируйте и ограничивайте ввод на сервере (длина, допустимые символы).
- HttpOnly, Secure, SameSite для куки.
- Subresource Integrity (SRI) для внешних скриптов.
- Логи и отчёты CSP (report-uri/report-to).
- Обновляйте библиотеки и проверяйте зависимости.
Короткие примеры
- Простой безопасный вывод текста:
element.textContent = userInput;
- Санитизация с DOMPurify перед вставкой HTML:
const clean = DOMPurify.sanitize(userInput, {ALLOWED_TAGS: ['b','i','a'], ALLOWED_ATTR: ['href']});
element.innerHTML = clean;
- Trusted Types + DOMPurify:
window.trustedTypes.createPolicy('default', {createHTML: (s)=>DOMPurify.sanitize(s)});
element.innerHTML = trustedTypes.defaultPolicy.createHTML(userInput);
Итого: не присваивайте необработанный ввод в innerHTML. Либо используйте textContent, либо валидный санитайзер + контекстное кодирование, дополните строгой CSP и (по возможности) Trusted Types. Это значительно снизит риск XSS.