Skip to content

Все для WordPress, веб-розробки — і не тільки

💡 Міжсайтовий скриптинг (XSS): що це і як захистити сайт у 2026

💡 Міжсайтовий скриптинг (XSS): що це і як захистити сайт у 2026

У 2019 майже 75% великих компаній зіткнулися з міжсайтовим скриптингом. Через сім років XSS нікуди не зник. Microsoft відзвітувала про 970 випадків XSS, закритих лише з січня 2024, а одна вразливість 2025 року в плагіні LiteSpeed Cache поставила під загрозу 7 мільйонів сайтів на WordPress.

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

Розберемо механіку XSS, три типи атак і конкретні шари захисту, які закривають сайт від міжсайтового скриптингу. З інструментами, прикладами коду та реальними кейсами WordPress.

💡 Швидкий огляд:

  • Що таке XSS і як зловмисник впроваджує шкідливий код на довірений сайт
  • Три типи міжсайтового скриптингу: збережений, відбитий і DOM-based, і чим вони відрізняються
  • Покрокове налаштування трьох шарів захисту: WAF, екранування виводу та Content Security Policy
  • Де шукати XSS-вразливості на своєму сайті та що робити, якщо атака вже сталася

Що таке міжсайтовий скриптинг

Схема атаки міжсайтового скриптингу на вебсайт

Cross-Site Scripting — це ін'єкційна атака, за якої зловмисник впроваджує шкідливий скрипт на сторінку довіреного сайту. Браузер жертви виконує цей код, бо сприймає його як частину легітимної сторінки. Звідси й назва: скрипт приходить «з crossing site boundary», з перетином межі сайту.

Технічно вектор атаки не обмежується JavaScript. Вразливості можливі в HTML, Flash, ActiveX і CSS. Але на практиці переважна більшість експлойтів націлені саме на JS. Причина, доступ до DOM-дерева, cookies, localStorage і можливість виконувати запити від імені користувача.

У WordPress вразливість майже завжди виникає через плагіни та теми, які неправильно обробляють користувацьке введення. Форми коментарів, пошукові рядки, контактні форми, сторінки логіну, будь-яке поле, яке приймає дані та виводить їх назад без фільтрації, стає точкою входу. За даними компанії Claranet, у 2024 році знайшли 2570 випадків відбитого та збереженого XSS у перевірених вебзастосунках.

Як працює XSS

Зловмиснику потрібні дві умови: точка входу для шкідливого коду та відсутність фільтрації на виході. На практиці це реалізується двома шляхами: через маніпуляцію користувацьким введенням і через обхід same-origin policy.

Впровадження через користувацьке введення

Найпоширеніший сценарій. Користувацьке поле, рядок пошуку, форма коментаря, поле завантаження файлу приймає не лише текст, а й виконуваний код. Якщо плагін або тема не екранують вивід, введений <script>alert('XSS')</script> виконається в браузері кожного, хто відкриє сторінку.

Проблема глибша, ніж здається. Навіть досвідчені розробники пропускають вектори XSS через, здавалося б, безневинні поля: завантаження SVG-файлу з вбудованим скриптом, введення в поле «ім'я користувача» під час реєстрації, параметри URL у редіректах. Одне поле без esc_url() або esc_attr(), і сайт відкритий.

В ідеальному світі поле пошуку приймає простий текст і нічого більше. У реальному WordPress екосистема з 60 000+ плагінів робить цю гарантію недосяжною, достатньо одного плагіна з echo $_GET['q'] без esc_html().

Обхід same-origin policy

Ілюстрація обходу політики однакового походження браузера

Same-origin policy, фундаментальне правило безпеки браузерів: скрипти з одного джерела не можуть читати дані з іншого. Сторінка Facebook і сторінка банку, відкриті в одному браузері, не обмінюються інформацією. Але в цього правила є ахіллесова п'ята, сесійні cookies.

Коли ви логінитеся на сайт, браузер створює сесійну cookie, яка підтверджує вашу особу під час кожного запиту. Без неї довелося б вводити пароль під час переходу на кожну нову сторінку. Проблема в тому, що браузер прикріплює цю cookie до будь-якого запиту до домену, включно із запитами, ініційованими шкідливим скриптом.

Схема атаки: зловмисник знаходить XSS-вразливість на сайті example.com → впроваджує скрипт, який читає document.cookie → надсилає сесійну cookie на свій сервер. Підсумок: повний доступ до акаунта жертви без знання пароля. Cookie сесії зберігають облікові дані, вміст кошика, інформацію про доставку, весь контекст користувача.

Три типи XSS-атак

Скриншот навчальної гри Google XSS Game для пошуку вразливостей

Класифікація XSS ґрунтується на тому, де і як шкідливий код потрапляє до жертви. Розрізняють три типи, і для захисту сайту потрібно розуміти механіку кожного.

Збережений XSS (Stored, тип I)

Найнебезпечніший тип. Шкідливий скрипт зберігається на сервері: у базі даних, логах, полі коментаря, і виконується щоразу, коли відкривають заражену сторінку. На WordPress це класичний сценарій: зловмисник залишає коментар із тегом <script>, плагін коментарів не фільтрує HTML, і скрипт спрацьовує в кожного відвідувача допису.

Особливість збереженого XSS у тому, що атаку не потрібно активувати через фішингове посилання. Жертва просто заходить на сторінку. У 2025 році вразливість CVE-2025-12709 у плагіні Interactions для WordPress, класичний stored XSS через недостатню санітизацію введення в селекторах подій.

Відбитий XSS (Reflected, тип II)

Зловмисник надсилає жертві посилання, яке містить шкідливий код у параметрах URL. Сервер «відбиває» цей код назад у відповіді, наприклад, у повідомленні про помилку пошуку або в рядку «Ви шукали: X». Браузер виконує скрипт, бо він надійшов у тілі відповіді від довіреного сервера.

Відбитий XSS потребує активної дії жертви, кліку за посиланням. Тому атаку часто маскують під легітимний URL у фішинговому листі. На WordPress типовий вектор, пошукові плагіни, які виводять пошуковий запит без esc_html().

DOM-based XSS (тип 0)

На відміну від перших двох, тут уразливість міститься не в серверному коді, а в клієнтському JavaScript. Шкідливі дані ніколи не потрапляють на сервер, вони обробляються прямо в браузері через небезпечні методи DOM-API, як-от innerHTML, document.write() або eval().

Джерелом даних слугує URL (через window.location), document.referrer або будь-яке інше контрольоване джерело на клієнті. Серверні логи чисті, атаку видно лише в браузері. Виявити такий XSS найскладніше, тому що WAF і серверні сканери його не бачать.

Чому XSS особливо небезпечний для WordPress

WordPress, ціль номер один для XSS з однієї причини: екосистема. З понад 60 000 плагінів у репозиторії далеко не всі проходять суворе рецензування на екранування виводу. Один плагін з уразливістю компрометує весь сайт.

У вересні 2025 року Microsoft опублікувала розбір того, чому XSS залишається загрозою через 25 років після появи. Ключовий висновок: складність сучасного вебстеку робить повне усунення XSS майже неможливим, занадто багато шарів, де може бути пропущене екранування.

Що отримує зловмисник через XSS на WordPress:

  • Доступ до адмінпанелі через викрадення сесійних cookies адміністратора
  • Впровадження прихованих посилань (SEO-спам)
  • Завантаження шкідливого ПЗ на комп’ютер відвідувача
  • Підміну платіжних реквізитів у WooCommerce
  • Масовий дефейс сторінок сайту

У поєднанні з соціальною інженерією XSS перетворюється на вектор для складних атак: від встановлення кейлогерів до підробки міжсайтових запитів.

Як захистити сайт від XSS: три шари

Три шари захисту WordPress від міжсайтового скриптингу

Захист від XSS не вирішується одним налаштуванням. Працює лише ешелонована оборона: плагіни безпеки перекривають грубі атаки, екранування виводу закриває технічні вектори, а Content Security Policy блокує виконання скриптів на рівні браузера.

Шар 1: плагіни безпеки та брандмауер

Перший рубіж, WordPress-плагін із Web Application Firewall. WAF фільтрує вхідні запити до того, як вони досягнуть коду плагінів, і блокує відомі сигнатури XSS-атак.

Вибираючи плагін безпеки, орієнтуйтеся на такий чек-лист:

  • Регулярне сканування на шкідливе ПЗ та відомі CVE у встановлених плагінах
  • Брандмауер із правилами для блокування XSS-патернів у запитах
  • Харденінг WordPress: вимкнення XML-RPC, зміна префікса таблиць, заборона редагування файлів з адмінки
  • Централізоване керування оновленнями всіх плагінів і тем
  • Резервне копіювання, щоб відновити сайт, якщо атака все ж пройшла

Добірку плагінів безпеки WordPress з детальним розбором функцій кожного інструмента шукайте в профільних оглядах на нашому сайті.

Шар 2: валідація та екранування виводу

Це головний технічний рубіж. Правило просте й не обговорюється: жодні користувацькі дані не виводяться в браузер без екранування. WordPress надає для цього вбудовані функції, і кожна прив'язана до конкретного контексту виводу.

Базовий арсенал розробника WordPress:

1// Для вывода внутри HTML-тегов — между <p> и </p>
2echo esc_html($user_input);
3
4// Для атрибутов HTML — внутри value="..."
5echo esc_attr($user_input);
6
7// Для URL в href, src и других атрибутах
8echo esc_url($user_url);
9
10// Для вывода текста внутри <textarea>
11echo esc_textarea($user_text);
12
13// Для JavaScript-переменных
14echo esc_js($user_data);
15
16// Для разрешенных HTML-тегов с удалением опасных атрибутов
17echo wp_kses_post($user_html);

Ключовий момент: вибір функції залежить від контексту. esc_html() в атрибуті href не врятує, зловмисник вставить javascript:alert('XSS'). І навпаки, esc_url() всередині параграфа пропустить тег <script>. Контекст визначає функцію.

Окремо варто згадати wp_kses(), потужний фільтр, який пропускає лише дозволені HTML-теги та атрибути. Для користувацького контенту (коментарі, описи профілів, користувацькі поля) це мінімально необхідний рівень фільтрації.

Шар 3: Content Security Policy (CSP)

CSP, HTTP-заголовок, який каже браузеру: «Виконуй скрипти лише з цих джерел». Це останній рубіж. Навіть якщо зловмисник впровадив <script> на сторінку, браузер його не виконає, тому що інлайн-скрипти не входять до білого списку.

Базова CSP-політика для WordPress:

1// В functions.php или через плагин
2function add_csp_header() {
3 header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;");
4}
5add_action('send_headers', 'add_csp_header');

Сувора політика ('strict-dynamic' замість 'unsafe-inline') безпечніша, але потребує налаштування nonce або хешів для кожного легітимного скрипта — це об'ємна робота на сайті з десятком активних плагінів. Почніть із report-only режиму, щоб зібрати логи порушень і не зламати фронтенд:

1Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint

CSP не замінює екранування. Він пом'якшує наслідки помилки, коли екранування десь пропустили.

Відео: XSS від азів до експлуатації

Щоб побачити XSS у дії та зрозуміти, як шукати вразливості на реальних сайтах, подивіться цей 30-хвилинний розбір:

Після перегляду повертайтеся до шарів захисту вище, тепер вони будуть зрозумілі на рівні механіки, а не лише на рівні назв функцій.

⁉️🤔 Часті питання

Чи допоможе оновлення WordPress і плагінів захистити від XSS?

Так, і це найбільш недооцінений крок захисту. Кожна нова версія плагіна часто закриває конкретні CVE, зокрема XSS-вразливості. Вразливість LiteSpeed Cache CVE-2025-12450 була закрита патчем протягом тижня після виявлення, але 7 мільйонів сайтів, які не оновилися, залишилися відкритими. Увімкніть автооновлення для всіх плагінів, втрата сумісності трапляється рідко, а пропущений патч б'є гарантовано.

Чи достатньо одного плагіна безпеки для захисту від XSS?

Ні. Плагін безпеки з WAF закриває відомі сигнатури атак, але не бачить zero-day вразливості та нестандартні вектори. Він має бути першим шаром, за яким ідуть екранування виводу в коді теми та CSP-заголовки. Три шари разом дають захист, якого не забезпечить жоден із них окремо.

Як перевірити, чи є на моєму сайті XSS-вразливості?

Почніть із безкоштовного сканера, WPScan, Sucuri SiteCheck, Qualys SSL Labs. Для глибшої перевірки запустіть OWASP ZAP (Zed Attack Proxy), open-source інструмент, який автоматично фаззить поля вводу та ловить відбитий XSS. Важливо: автоматичні сканери не бачать DOM-based XSS, для нього потрібен ручний аудит JavaScript-коду сайту.

Чи можна повністю виключити XSS на великому сайті?

Повне виключення XSS на сайті з десятками плагінів і кастомною темою, завдання, близьке до ідеалу, але важко досяжне повністю. Кожен новий плагін, кожне оновлення теми, кожен кастомний сніпет у functions.php, потенційна точка входу. Реалістична мета: три шари захисту, автооновлення, щоквартальний аудит і CSP у report-only режимі. Так ви відловите переважну більшість атак на ранній стадії.

Що робити, якщо сайт уже атакований через XSS?

Негайно змініть усі паролі та скиньте сесійні ключі у wp-config.php через генератор WordPress. Потім відновіть сайт із чистої резервної копії. Після відновлення встановіть плагін безпеки, оновіть усі плагіни та теми до останніх версій, додайте CSP-заголовок у functions.php. Змінювати паролі потрібно, тому що XSS часто краде сесійні cookies адміністратора.

XSS і SQL-ін'єкція — це одне й те саме?

Ні, хоча обидві належать до injection-атак. SQL-ін'єкція б'є в базу даних через SQL-запит, зловмисник може прочитати, змінити або видалити таблиці. XSS б'є в браузер користувача через JavaScript, мета, вкрасти сесію, показати фішингову форму, підмінити контент сторінки. У них різні вектори, різні функції захисту ($wpdb->prepare() для SQL, esc_html() для XSS) і різні наслідки. Але на практиці вони часто йдуть у зв'язці: XSS використовують для доставки SQL-ін'єкції через адмін-панель.

Чи варто боятися XSS у 2026

XSS не зник, але захист від нього став інженерною рутиною, а не магією. Три шари, плагін із WAF, екранування виводу в усіх точках контакту з користувачем і CSP-заголовок, закривають переважну більшість векторів. Плюс автооновлення плагінів і тем, щоб патчі доїжджали раніше за експлойти.

Якщо ви прямо зараз не використовуєте жодного з цих шарів, почніть із встановлення плагіна безпеки та ввімкнення автооновлень в адмінці WordPress. Це займе 10 хвилин і закриє найгрубіші входи. А потім повертайтеся до цієї статті, коли будете готові впровадити екранування та CSP.