Ландшафт безпеки фронтенду, що розвивається
Протягом багатьох років у галузі панувало небезпечне помилкове уявлення: безпека — це «проблема бекенду». У цій застарілій моделі фронтенд-розробники відповідали за «скло» — UI/UX — тоді як основна робота з автентифікації, валідації даних та протидії загрозам відбувалася за фаєрволом.
На порозі 2025 та 2026 років ця межа фактично зникла. З поширенням складних Single Page Applications (SPA), мікрофронтендів та edge computing, саме фронтенд став основною поверхнею атаки. Сучасні браузери впровадили потужні API для захисту від витончених загроз, але вони потребують активного впровадження з боку розробників. Водночас глобальні норми, такі як Регламент ЄС про кіберстійкість (CRA), вимагають впровадження принципу «Security-by-Design», роблячи управління вразливостями юридичною вимогою, а не просто гарною практикою.
Цей посібник досліджує фундаментальні основи безпеки фронтенду в сучасну епоху, надаючи технічну глибину, необхідну для створення стійких та відповідних стандартам вебдодатків.
1. Сучасна автентифікація: OAuth 2.1 та Zero-Trust
Ландшафт автентифікації пройшов через значну консолідацію. Станом на 2025 рік OAuth 2.1 замінив розрізнені RFC версії OAuth 2.0, встановивши більш безпечний базовий рівень для клієнтських додатків.
Смерть Implicit Grant та поява PKCE
Найсуттєвішою зміною в OAuth 2.1 є офіційне видалення потоку Implicit Grant. Раніше поширений у SPA, цей потік повертав токени доступу безпосередньо у фрагменті URL, що робило їх вразливими до «витоку токенів доступу» через історію браузера або заголовки referrer.
Новим стандартом для всіх фронтенд-додатків є Authorization Code Flow з PKCE (Proof Key for Code Exchange). PKCE гарантує, що навіть якщо зловмисник перехопить код авторизації, він не зможе обміняти його на токен без секретного «code verifier», який ніколи не залишає пам'ять клієнта.
// Концептуальний приклад генерації PKCE challenge у фронтенд-сервісі
async function generatePKCE() {
const verifier = generateRandomString(128);
const challengeBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = base64UrlEncode(challengeBuffer);
// Зберігаємо verifier у пам'яті (не в LocalStorage!) для кроку обміну
sessionStorage.setItem('pkce_verifier', verifier);
return challenge;
}Перехід до архітектури Zero-Trust
В архітектурі фронтенду Zero-Trust ми більше не припускаємо, що користувач є «безпечним» лише тому, що він має валідну сесійну куку (cookie). Кожен критичний виклик API розглядається як унікальний запит, який має бути авторизований. Це часто передбачає використання короткочасних токенів доступу з обмеженою областю дії (scopes). Замість єдиної ролі «admin» розробники тепер впроваджують гранулярні дозволи, які перевіряються при кожній взаємодії з UI та наступному запиті до API.

2. Нейтралізація ін'єкцій за допомогою Trusted Types та санітизації
Міжсайтовий скриптинг (XSS) залишається однією з головних загроз, але методологія запобігання йому змістилася від реактивного «екранування» до проактивної безпеки на основі політик.
Впровадження Trusted Types API
Trusted Types API докорінно змінює правила гри для запобігання DOM-based XSS. Він дозволяє розробникам заблокувати «injection sinks» — небезпечні функції, такі як .innerHTML, eval() або document.write(). Після активації через Content Security Policy (CSP) браузер відмовлятиметься приймати звичайні рядки для цих функцій. Замість цього ви повинні передати об'єкт «Trusted Type», створений за допомогою заздалегідь визначеної політики.
// 1. Визначаємо політику (зазвичай у точці входу вашого додатка)
const escapeHTMLPolicy = trustedTypes.createPolicy("myAppPolicy", {
createHTML: (input: string) => {
// Використовуємо бібліотеку накшталт DOMPurify для санітизації вводу
return DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true });
}
});
// 2. Використання політики
const userInput = "<img src=x onerror=alert(1)>";
const secureElement = document.getElementById("content");
// Це викличе TypeError, якщо Trusted Types активовано:
// secureElement.innerHTML = userInput;
// Це безпечний та відповідний стандартам спосіб:
secureElement.innerHTML = escapeHTMLPolicy.createHTML(userInput);Контекстне кодування виводу
Хоча сучасні фреймворки, такі як React та Vue, виконують базове екранування HTML за замовчуванням, вони не захищають у всіх контекстах. Розробники повинні бути пильними щодо:
- Контекст атрибутів:
href="javascript:alert(1)"не перехоплюється стандартним екрануванням. - Контекст CSS: Значення в тегах
style, які контролюються користувачем, можуть призвести до витоку даних. - Контекст JSON: Передача даних із сервера безпосередньо в тег
<script>вимагає специфічного екранування JSON, щоб запобігти виходу за межі рядка.
DOMPurify у 2026 році
DOMPurify (v3.3.1+) залишається галузевим стандартом. Сучасні версії оптимізовані за допомогою WebAssembly (Wasm) для майже нативної продуктивності та пропонують глибоку інтеграцію з Trusted Types API. При роботі з контентом, створеним користувачами (коментарі, профілі тощо), санітизація має відбуватися якомога ближче до «sink» (точки впорскування).

3. Зміцнення браузера за допомогою CSP та безпечних кук
Браузер надає кілька механізмів для ізоляції вашого додатка від шкідливих скриптів. Правильне їх налаштування є ознакою досвідченого фронтенд-розробника.
Content Security Policy (CSP) Level 3
Надійна CSP — це ваша остання лінія оборони. У 2025 році ми відійшли від масивних «білих списків» (які важко підтримувати) до Strict CSP, що використовують нонси (nonces) та strict-dynamic.
- Нонси (Nonces): Унікальний, криптографічно стійкий випадковий рядок, що генерується для кожного запиту. Виконуватися будуть лише скрипти з відповідним атрибутом
nonce. - Strict-Dynamic: Ця директива вказує браузеру, що якщо скрипт є довіреним (через nonce), то будь-які скрипти, які він динамічно завантажує, також повинні вважатися довіреними. Це спрощує управління складними деревами залежностей.
Приклад заголовка CSP:
Content-Security-Policy:
object-src 'none';
script-src 'nonce-rAnd0m123' 'strict-dynamic' https:;
base-uri 'none';Безпечне управління куками та CHIPS
Зберігання сесійних токенів — це вічна тема для дискусій. Консенсус на 2025–2026 роки чіткий: Уникайте LocalStorage для конфіденційних токенів.
Замість цього використовуйте куки з такими обов'язковими атрибутами:
- HttpOnly: Запобігає доступу через JavaScript, пом'якшуючи наслідки XSS.
- SameSite=Lax/Strict: Запобігає підробці міжсайтових запитів (CSRF), обмежуючи умови надсилання кук.
- Partitioned (CHIPS): Cookies Having Independent Partitioned State (CHIPS) дозволяють розробникам використовувати «парціоноване» сховище. Це критично важливо для сторонніх вбудованих елементів (наприклад, віджетів оплати), щоб підтримувати стан без дозволу на міжсайтове відстеження, що відповідає сучасним вимогам приватності.
Subresource Integrity (SRI)
Атаки на ланцюжок поставок (supply chain attacks) почастішали. Якщо ви завантажуєте бібліотеку з CDN (наприклад, Google Fonts або певну JS-утиліту), ви повинні використовувати SRI. Це гарантує, що якщо CDN буде зламано і файл змінено, браузер відмовиться його виконувати.
<script src="https://example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>4. Безпечна комунікація та цілісність вводу
Фронтенд-додатки рідко існують ізольовано. Вони спілкуються з API, іншими вікнами (iframe) та воркерами (workers).
Безпечне впровадження postMessage
При використанні window.postMessage для міждоменної комунікації двома найпоширенішими помилками є відсутність перевірки походження (origin) відправника та неможливість вказати цільове походження отримувача.
// Отримувач: Завжди перевіряйте, хто з вами спілкується
window.addEventListener("message", (event) => {
const trustedOrigins = ["https://app.trusted.com", "https://auth.trusted.com"];
if (!trustedOrigins.includes(event.origin)) {
console.error("Заблоковано повідомлення з недовіреного джерела:", event.origin);
return;
}
// Завжди безпечно парсіть дані
try {
const message = JSON.parse(event.data);
handleMessage(message);
} catch (e) {
console.error("Невірний формат повідомлення");
}
});Різниця між валідацією та санітизацією
Поширеною помилкою є покладання на клієнтську валідацію як на захід безпеки.
- Валідація: Це функція UX. Вона каже користувачеві: «це недійсна адреса електронної пошти». Її легко обійти зловмиснику за допомогою проксі-інструментів, таких як OWASP ZAP.
- Санітизація: Це функція безпеки. Вона видаляє небезпечні символи з вводу перед його збереженням або рендерингом.
- Примусове виконання (Enforcement): Логіка безпеки завжди повинна виконуватися на сервері. Робота фронтенду полягає в тому, щоб переконатися, що дані, надіслані на сервер, правильно сформовані, а дані, отримані від сервера, безпечно відображаються.
5. Відповідність стандартам, залежності та фактор ШІ
Роль фронтенд-розробника тепер включає певний рівень юридичної та регуляторної обізнаності.
Регламент ЄС про кіберстійкість (CRA) та SBOM
До вересня 2026 року CRA ЄС вимагатиме від програмних продуктів надання Специфікації програмного забезпечення (SBOM). Для фронтенд-розробників це означає, що ви повинні мати можливість звітувати за кожен NPM-пакет, транзитивну залежність та скрипт, розміщений на CDN у вашому додатку.
Такі інструменти, як Snyk, Dependabot або Socket, більше не є опціональними. Вони мають бути інтегровані у ваш CI/CD пайплайн для автоматичного виявлення вразливостей у вашому package-lock.json.
Ризики коду, створеного ШІ
Поява ШІ-помічників для написання коду (Cursor, GitHub Copilot) породила новий клас вразливостей: галюцинації залежностей ШІ. Були задокументовані випадки, коли ШІ пропонує неіснуючі пакети, які зловмисники потім реєструють в NPM для здійснення атак на ланцюжок поставок.
Найкраща практика: Ніколи не мерджіть «наосліп» логіку безпеки або додані залежності, згенеровані ШІ. Кожен рядок коду, створений ШІ, повинен проходити ручну перевірку безпеки розробником.

Часті питання
Чи є безпека фронтенду відповідальністю фронтенд-розробника?
Так, сучасна веб-архітектура переклала значну частину відповідальності на сторону клієнта. Поки бекенд захищає базу даних та серверну логіку, фронтенд-розробник відповідає за захист сесії користувача, запобігання XSS та впровадження безпечних політик на рівні браузера.
Які найпоширеніші ризики безпеки фронтенду?
Найбільш розповсюджені ризики включають міжсайтовий скриптинг (XSS), небезпечне зберігання конфіденційних токенів у LocalStorage та вразливості в ланцюжку поставок через сторонні залежності. Крім того, значною проблемою залишається неправильне налаштування Content Security Policy (CSP) та Cross-Origin Resource Sharing (CORS).
Як запобігти XSS у сучасних фреймворках, таких як React або Vue?
Хоча фреймворки забезпечують екранування за замовчуванням, ви повинні уникати «люків» на кшталт dangerouslySetInnerHTML або v-html, якщо дані не санітизовані за допомогою DOMPurify. Крім того, впровадження Trusted Types API забезпечує рівень захисту на рівні браузера, який виловлює спроби ін'єкцій, навіть якщо захист на рівні фреймворку було обійдено.
Чи безпечно зберігати токени автентифікації в LocalStorage?
Загалом, ні. LocalStorage доступний для будь-якого JavaScript, що працює в тому самому домені (origin), а це означає, що вразливість XSS може призвести до негайного викрадення токена. Набагато безпечніше використовувати HttpOnly та Secure куки або зберігати токени в пам'яті за допомогою стратегії Refresh Token Rotation.
Яка різниця між валідацією вводу та санітизацією?
Валідація вводу перевіряє, чи відповідають дані певному формату (наприклад, валідна пошта) для цілей UX, тоді як санітизація видаляє або кодує небезпечні символи (наприклад, <script>), щоб запобігти їх виконанню. Валідація відбувається перед обробкою, тоді як санітизація — перед рендерингом або збереженням даних.
Висновок
Веббезпека у 2025 та 2026 роках — це багатошарова дисципліна. Як фронтенд-розробники, ми є охоронцями браузерного середовища користувача. Впроваджуючи OAuth 2.1, використовуючи Trusted Types та підтримуючи суворий контроль над SBOM, ми можемо створювати додатки, які є не лише функціональними, але й стійкими до дедалі складнішого ландшафту загроз.
Перехід до «Security-by-Design» — це не просто регуляторний бар'єр, це можливість побудувати довіру з користувачами. Почніть з аудиту ваших поточних заголовків за допомогою Mozilla Observatory, сканування залежностей через Snyk та перенесення конфіденційних токенів із LocalStorage. Безпека — це не разове завдання, а постійне прагнення до досконалості в інженерії.