Що таке XSS і як захистити вебзастосунок

Автор: Опубліковано

Коротко: XSS (Cross-Site Scripting) — це вразливість, через яку браузер виконує недовірений код у контексті відвідуваної сторінки. Найчастіше вона виникає, коли застосунок обробляє дані користувача як фрагмент сторінки або коду, а не як звичайний текст. Захист полягає передусім у безпечному відображенні даних, а не лише в блокуванні підозрілого введення.

Як працює XSS і що може зробити зловмисник

Браузер інтерпретує HTML як структуру сторінки, а JavaScript — як інструкції для виконання. Якщо застосунок вставить неперевірений вміст туди, де браузер сприйме його як код, зловмисник зможе вплинути на роботу сторінки в іншого користувача. Джерелом такого вмісту може бути коментар, параметр адреси, назва профілю або відповідь зовнішнього сервісу.

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

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

Три найчастіше описувані різновиди XSS

Цей поділ допомагає визначити, звідки надходить небезпечний вміст і де саме застосунок його обробляє:

Ці поняття не завжди взаємовиключні. «Збережений» і «відображений» описують переважно шлях надходження даних, а «DOM-based» вказує на місце небезпечної обробки. Вміст, збережений у базі, також може призвести до DOM-based XSS.

Простий приклад: текст, сприйнятий як HTML

Припустімо, застосунок відображає ім’я користувача. Запускайте наведений нижче приклад лише у власному тестовому середовищі або там, де маєте на це явний дозвіл:

const imia = '<img src="x" onerror="alert(\'Тест XSS\')">';
const element = document.querySelector('#pryvitannia');
element.innerHTML = imia;

Властивість innerHTML вказує браузеру інтерпретувати значення як HTML. Якщо зображення не завантажиться, обробник помилки може викликати alert, тобто показати вікно з повідомленням. Це демонстрація виконання коду, а не приклад викрадення даних; додаткові засоби захисту браузера чи сторінки можуть її заблокувати.

Якщо ім’я має відображатися як звичайний текст, правильне рішення таке:

const imia = '<img src="x" onerror="alert(\'Тест XSS\')">';
const element = document.querySelector('#pryvitannia');
element.textContent = imia;

Властивість textContent відобразить заданий рядок без створення зображення та без виконання інструкції, що міститься в ньому. Різниця принципова: дані залишаються даними. Не потрібно вгадувати, які слова чи теги можуть бути небезпечними.

Як захистити застосунок від XSS

Добирайте захист відповідно до місця використання даних. Кодування вихідних даних полягає в поданні спеціальних символів так, щоб вони не сприймалися як синтаксис. Для тексту в HTML потрібні одні правила, для значення атрибута, адреси URL чи фрагмента JavaScript — інші. Заміна лише кутових дужок < і > не захищає в усіх цих ситуаціях.

Для відображення звичайного тексту використовуйте безпечні механізми шаблонів та інтерфейси на кшталт textContent. Автоматичне кодування у фреймворку допомагає, але його можна обійти функцією, що вставляє необроблений HTML. Такі винятки потребують окремої перевірки.

Якщо користувачам справді потрібне форматування HTML, використовуйте бібліотеку для санітизації, яку активно підтримують, наприклад DOMPurify. Санітизація видаляє недозволені елементи й атрибути за визначеними правилами. Власний фільтр на основі кількох регулярних виразів не забезпечує рівноцінного захисту.

Валідація, тобто перевірка допустимого формату даних, залишається корисною: поле віку має приймати число, а адреса посилання — використовувати дозволену схему. Однак це не замінює безпечного відображення. Захисту лише форми також недостатньо, адже дані можуть потрапити до застосунку іншим шляхом.

Додаткові рівні захисту обмежують наслідки помилок. CSP (Content Security Policy) дає змогу визначити правила виконання скриптів, але її ефективність залежить від налаштувань. Атрибут HttpOnly блокує зчитування файлу cookie через JavaScript, проте не блокує всіх дій, які шкідливий код може виконати в активному сеансі.

Із чого почати перевірку власного сайту

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

Наступний крок — тест в ізольованому середовищі: з’ясуйте, чи введений вміст відображається як текст, чи змінює структуру сторінки. Після виправлення додайте регресійний тест, який виявить, якщо ці дані знову почнуть оброблятися як HTML.

Дивіться також: Що таке 2FA?

Читайте також

Дізнайтеся, як PHP-FPM обробляє запити PHP, чим відрізняється від вебсервера та як налаштувати процеси під трафік і ресурси хостингу.
Дізнайтеся, як BIND обслуговує DNS, чим відрізняються його серверні ролі та коли варто розгортати його самостійно замість керованої послуги.
Дізнайтеся, що означають польський реєстр і номер REGON, чим вони відрізняються від NIP та KRS і як перевірити дані підприємства.