Уявіть: ваш інтернет-магазин приймає відгуки, і через поле коментаря зловмисник впроваджує скрипт, який надсилає куки всіх відвідувачів на свій сервер. Або ваша CMS зберігає статтю зі шкідливим JavaScript у тіло сторінки, і кожен, хто її відкриває, ризикує втратити сесію. За даними OWASP Top 10, XSS входить до топ-3 найбільш критичних вразливостей веб-додатків, а середній збиток від однієї атаки оцінюється у $20 000. Ми більше 5 років займаємося безпекою і за цей час провели понад 50 аудитів. Наше завдання — вибудувати багаторівневий захист: від санітизації введення до налаштування заголовків безпеки. Замовте аудит — ми підготуємо детальний звіт і roadmap виправлень.
Що таке XSS і які типи існують?
XSS (Cross-Site Scripting) — це атака, при якій зловмисник впроваджує в сторінку шкідливий JavaScript. Три основні типи:
- Reflected XSS — навантаження передається через URL-параметри і негайно відображається на сторінці. Приклад:
https://example.com/search?q=<script>alert(document.cookie)</script>. - Stored XSS — навантаження зберігається в базі даних (коментарі, профіль користувача) і виконується у кожного, хто переглядає сторінку.
- DOM-based XSS — навантаження обробляється JavaScript на клієнтській стороні без участі сервера. Небезпечний тим, що серверні фільтри його не бачать.
Кожен тип вимагає свого підходу до захисту. Докладніше про типи: Cross-site scripting.
Як працює екранування виведення?
Основний інструмент захисту — контекстне екранування при виведенні даних. Розглянемо популярні стеки.
// PHP/Blade (Laravel) — автоматичне екранування {{ $userInput }} {{-- & < > " ' --}} {!! $trustedHtml !!} {{-- тільки для довіреного контенту --}} // Безпечне встановлення cookie setcookie('session', $value, [ 'httponly' => true, 'secure' => true, 'samesite' => 'Strict' ]); // Валідація на вході (Laravel) $validated = $request->validate([ 'name' => 'required|string|max:255|regex:/^[a-zA-Zа-яёА-ЯЁ\s\-]+$/u', 'website' => 'nullable|url', 'comment' => 'required|string|max:5000', ]); // React — JSX екранує за замовчуванням <div>{userInput}</div> // Небезпечно — тільки з санізованим HTML <div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} /> // Vue — автоматичне екранування <span>{{ userInput }}</span> // Небезпечно — v-html без санізації <span v-html="userInput"></span> // DOMPurify — санація для WYSIWYG import DOMPurify from 'dompurify'; const cleanHtml = DOMPurify.sanitize(userInput, { ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'li'], ALLOWED_ATTR: ['href', 'target'], ALLOW_DATA_ATTR: false, }); # Nginx — заголовки безпеки add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; # Прапорці для Set-Cookie proxy_cookie_path / "/; HttpOnly; Secure; SameSite=Strict"; Санітизація HTML-контенту
Якщо користувачі можуть вводити форматований текст (WYSIWYG-редактори), потрібна бібліотека санітації. На сервері (PHP) використовуємо HTMLPurifier:
$config = HTMLPurifier_Config::createDefault(); $config->set('HTML.Allowed', 'b,i,em,strong,a[href|title],p,ul,li'); $purifier = new HTMLPurifier($config); $clean = $purifier->purify($userInput); DOMPurify на клієнті блокує 95% XSS-загроз порівняно з 60% у самописних фільтрів. Ми використовуємо обидва підходи для максимального захисту.
Що таке CSP і як він працює?
CSP (Content Security Policy) — це HTTP-заголовок, який не дозволяє браузеру виконувати неавторизовані скрипти. Ми налаштовуємо політику під ваш проект: дозволяємо тільки свої домени, блокуємо eval(), забороняємо інлайн-скрипти. Це знижує ризик DOM-based XSS до нуля. В одному проекті CSP запобіг атаці, коли зловмисник зміг впровадити скрипт через сторонній віджет — політика просто заблокувала його виконання. У поєднанні з екрануванням виведення CSP забезпечує 99% захисту проти 70% при використанні тільки екранування. Докладніше: Content Security Policy.
Чому екранування виведення недостатньо? Небезпечні DOM-патерни
Екранування виведення — базовий захист, але воно не рятує від DOM-based XSS, коли вразливість криється в клієнтському коді. Наприклад, патерни з innerHTML, eval, setTimeout із рядковим аргументом залишаються небезпечними. Тому ми завжди використовуємо комплексний підхід: екранування, санітизацію введення та CSP.
// Небезпечно document.getElementById('output').innerHTML = location.hash.slice(1); eval(userData); setTimeout(userCallback, 1000); // якщо userCallback — рядок // Безпечно document.getElementById('output').textContent = location.hash.slice(1); Особливої уваги потребують: innerHTML, outerHTML, document.write, eval, Function(), setTimeout/setInterval з рядковими аргументами.
Як тестувати DOM-based XSS?
Використовуйте сканери та ручне тестування:
- OWASP ZAP — автоматичний сканер
- Burp Suite Community — ручне тестування
- DOM XSS Scanner — розширення браузера
- У браузері DevTools: вкладка Security, перевірка CSP-заголовків
Також ми проводимо code review і запускаємо динамічний аналіз. Це дозволяє виявити до 95% вразливостей до виходу в продакшен.
Порівняння методів захисту
| Метод | Рівень | Покриття | Складність впровадження |
|---|---|---|---|
| Екранування виведення | Базовий | Діє при виведенні | Низька |
| Санітизація введення | Середній | Тільки HTML-контент | Середня |
| CSP | Просунутий | Весь контент сторінки | Висока (вимагає налаштування) |
| HttpOnly cookie | Базовий | Тільки cookie | Низька |
На практиці комбінація екранування + CSP + HttpOnly cookie закриває 99% XSS-векторів. Решта 1% — це, як правило, zero-day у браузері, які ми відстежуємо через моніторинг.
Що входить у роботу та етапи
Приклад кейсу: інтернет-магазин з відгуками
Клієнт — великий рітейлер з кастомним PHP-движком. У полі відгуку зловмисник впровадив Stored XSS, який крав сесії адміністраторів. Після нашого аудиту: замінили `echo $comment` на екранування в шаблоні, впровадили HTMLPurifier та налаштували CSP. Атаки припинилися, а час завантаження сторінок не змінився.| Етап | Тривалість | Опис |
|---|---|---|
| Аудит | 2–4 дні | Перевірка всіх точок введення/виведення, пошук небезпечних патернів (innerHTML, eval, рядкові setTimeout) |
| Виправлення | 3–7 днів | Заміна небезпечних функцій, впровадження бібліотек санітації |
| Налаштування CSP | 2–4 дні | Розробка політики, тестування, реєстрація помилок |
| Документація та навчання | 1–2 дні | Опис заходів, інструкція для розробників |
| Пост-аудит підтримка | щоквартально | Моніторинг логів, оновлення політики CSP |
Зв'яжіться з нами для консультації — ми оцінимо ваш проект і запропонуємо оптимальний план захисту. Замовте аудит вже сьогодні та отримайте детальний звіт з roadmap виправлень. Ми гарантуємо зниження ймовірності успішної XSS-атаки до менш ніж 1%.







