Одна з найвідоміших вразливостей, CSRF – це атака на стороні клієнта, яка може спонукати здійснювати небажані дії в межах сесії користувача, включно з перенаправленням на шкідливий сайт або крадіжкою даних сесії. Правильне генерування та використання анти-CSRF токенів є критично важливим для захисту юзерів.
Що таке анти-CSRF токен?
Ідея анти-CSRF токенів (іноді просто CSRF токенів) доволі проста: браузеру користувача надається фрагмент інформації (токен), який потім повинен бути відправлений назад для підтвердження, що запит є легітимним.
Щоб бути ефективним, токен має бути унікальним і неможливим для вгадування сторонньою особою. Вебсайт має перевірити цей токен і обробляти HTTP-запити лише після успішної валідації, щоб гарантувати, що лише легітимний користувач може робити запити у межах своєї автентифікованої сесії.
Як працює CSRF?
Зазвичай атака полягає в тому, що користувача спонукають перейти за шкідливим посиланням, яке виконує небажані дії в активній сесії користувача вебсайту.
У додатку без захисту від CSRF сервер не перевіряє, звідки саме надійшов запит, – він бачить лише, що він був виконаний авторизованим користувачем (передані cookie та інші облікові дані). Це дозволяє зловмиснику використовувати сесію юзера для небажаних дій.
Приклад вразливої сторінки без CSRF-токена
Як приклад можна взяти вебсайт www.example.com без будь-якого захисту від CSRF. Щоб опублікувати повідомлення у своєму профілі в застосунку, користувач заповнює просту HTML-форму та натискає кнопку “Надіслати”:
<form action="/action.php" method="post">
Subject: <input type="text" name="subject"/><br/>
Content: <input type="text" name="content"/><br/>
<input type="submit" value="Submit"/>
</form>
Ця дія змушує веббраузер надсилати запит POST на сервер з будь-якими даними, введеними користувачем, які надсилаються в параметрах теми та вмісту:
POST /post.php HTTP/1.1
Host: example.com
subject=Я сьогодні почуваюся досить добре&content=Я щойно з'їв печиво з шоколадною крихтою
Якщо користувач увійшов у систему, а зловмисник знає синтаксис запиту, він може змусити юзера натиснути спеціально створене посилання на сайт злочинця, що спричинить CSRF-атаку, дозволивши опублікувати рекламу в профілі цього користувача. Код, розміщений на сайті злочинця, змусить браузер юзера внутрішньо обробити та надіслати HTML-форму, подібну до:
<form action="https://example.com/action.php" method="post">
<input type="text" name="subject" value="Купіть мій продукт!"/>
<input type="text" name="content" value="Щоб купити продукт, перейдіть за цим посиланням: example.biz!"/> <input type="submit" value="Submit"/>
</form>
<script>
document.forms[0].submit();
</script>
Якщо сайт вразливий до CSRF, веббраузер користувача надішле запит POST, подібний до наступного:
POST /post.php HTTP/1.1
Host: example.com
subject=Купіть мій продукт!&content=Щоб купити продукт, перейдіть за цим посиланням: example.biz!
Додавання простого CSRF-токена
Щоб захиститися від атаки, можна використовувати токени: сервер генерує його при вході користувача, передає його браузеру, а всі форми в додатку мають містити приховане поле з цим токеном.
За умови належної генерації та перевірки токенів (як у прикладі нижче), це має усунути вразливість CSRF:
<form>
Subject: <input type="text" name="subject"/><br/>
Content: <input type="text" name="content"/><br/>
<input type="submit" value="Submit"/>
<input type="hidden" name="token" value="dGhpc3Nob3VsZGJlcmFuZG9t"/>
</form>
Сервер приймає та обробляє запити POST лише якщо вони містять потрібний токен у параметрі запиту, наприклад:
POST /post.php HTTP/1.1 Host: example.com subject=Я сьогодні почуваюся досить добре&content=Я щойно з'їв печиво з шоколадною крихтою&token=dGhpc3Nob3VsZGJlcmFuZG9t
Як безпечно генерувати та перевіряти анти-CSRF токени
Існує багато різних способів створення та перевірки анти-CSRF токенів залежно від вебсайту. Перш за все, якщо платформа або мова програмування вже містять функцію запобігання CSRF, зазвичай краще покладатися на неї або знайти надійну зовнішню бібліотеку, а не намагатися реалізувати власну.
Але також існує ряд найкращих практик:
- Токени мають бути криптографічно міцними (достатньо рандомізованими) і мати щонайменше 128 біт для протидії brute-force атакам.
- Уникати повторного використання токенів – зробити їх специфічними для сесії, регенерувати після важливих дій і встановлювати термін валідності.
- Сервер повинен перевіряти токени щоразу, використовуючи безпечний спосіб порівняння (наприклад, через перевірку хешів).
- Ніколи не передавати токени по незашифрованому HTTP трафіку і не включати їх у запити GET, щоб вони не потрапляли в URL.
- Передавати анти-CSRF токени в SameSite cookie. Додатково, використання атрибута HTTPOnly може запобігти доступу до cookie через JavaScript.
- Забезпечити відсутність вразливостей типу XSS (міжсайтовий скриптинг), оскільки зловмисник може використати цей недолік для обходу захисту від CSRF.
Використання додаткових рівнів захисту від CSRF
Окремий токен для кожної форми
Для балансу між безпекою та зручністю можна генерувати окремий токен для кожної форми. Щоб зробити це, потрібно хешувати токен разом з іменем файлу форми, наприклад:
hash_hmac('sha256', 'post.php', $_SESSION['internal_token'])
Для перевірки треба порівняти два хеші. Якщо токен дійсний, і була використана та сама форма – вони збігатимуться.
Окремий токен для кожного запиту
Можна використовувати окремий токен для кожного запиту, просто анулюючи дію кожного після його перевірки. Але у цього методу є ряд недоліків, які слід врахувати:
- Потрібно постійно генерувати нові токени, що може бути великим навантаженням для сервера.
- Користувач не зможе використовувати декілька вкладок одночасно.
- Неможливо використовувати кнопку “назад” у браузері – доведеться реалізовувати внутрішню навігацію в додатку.
Захист від CSRF без збереження стану (stateless)
Зазвичай кожен токен зберігається на сервері для перевірки, що дозволяє серверу запам’ятовувати стан сесії. У деяких випадках, наприклад, якщо вебсторінка або програма дуже навантажена та/або обсяг сховища на сервері обмежений, можна використовувати захист від CSRF без збереження стану (stateless), щоб уникнути необхідності зберігати токени на стороні сервера.
Найпростіший спосіб зробити це – використовувати патерн файлів cookie подвійного надсилання (double-submit cookie pattern), підписаний або непідписаний.
Це працює так, що сервер встановлює випадкове значення в файлі cookie ще до того, як користувач пройде автентифікацію. Потім сервер очікує, що це значення буде надіслано з кожним запитом, наприклад, за допомогою прихованого поля форми.
Патерн спирається лише на випадкове значення, яке зловмисник не може вгадати, тоді як підписаний патерн додатково шифрує це значення за допомогою секретного ключа на стороні сервера.
Деякі реалізації також використовують позначки часу як частину процесу генерації та перевірки токенів.
Захист від CSRF в асинхронних (Ajax) запитах
Багато сучасних додатків замість традиційних HTML-форм використовують Ajax. У такому випадку впровадження стандартних анти-CSRF токенів може бути складним.
Альтернативний підхід полягає у використанні власного заголовка для запитів клієнта. Якщо він використовується, бекенд відхилить будь-які запити без цього HTTP-заголовка.
Але варто зазначити, що надто слабке налаштування CORS (спільне використання ресурсів між джерелами, cross-origin resource sharing) може дозволити зловмиснику визначати файли cookie, а також власні заголовки, тому треба бути обережними, обмежуючи це джерелами, які команди точно контролюють.
Як приклад застосування захисту від CSRF за замовчуванням, можна перевизначити прототипний метод JavaScript XMLHttpRequest.open() на той, який автоматично встановлює власний анти-CSRF заголовок. Подібні механізми доступні в популярних бібліотеках та фреймворках.
Деякі старіші онлайн-ресурси радять не використовувати анти-CSRF токени для API-інтерфейсів через непотрібність, але оскільки зараз багато вебсайтів повністю орієнтовані на API, це створює ризики. Як і у випадку з Ajax-запитами, кастомні заголовки запитів – це хороший спосіб реалізації захисту від CSRF для API.
Анти-CSRF токени для форм входу
Поширеною помилковою думкою є те, що анти-CSRF токени потрібні лише тоді, коли користувач увійшов у систему, тому захист від CSRF для форм входу не потрібен.
Хоча і не можна безпосередньо видати себе за користувача до входу, відсутність захисту від CSRF у формах входу може дозволити атаки, які розкривають конфіденційну інформацію після обману юзера, змушуючи його увійти як зловмисник.
Це можна виконати наступним чином:
Увага: дана інформація надається виключно з метою ознайомлення з ризиками та розуміння специфіки атак професіоналами з кібербезпеки, і не спонукає використовувати написане для зловмисних цілей.
- Злочинець реєструє обліковий запис.
- Потім обдурює користувача, щоб він зайшов у вебсайт, використовуючи облікові дані зловмисника. Для цього може знадобитися лише невелика соціальна інженерія.
- Ціль використовує вебсайт, не підозрюючи, що вона ввійшла в систему як злочинний хакер.
- Зловмисник може відстежувати дані цілі, включаючи активність, особисту інформацію або збережені фінансові дані, потенційно виконуючи дії від її імені (наприклад, здійснення покупок за допомогою збережених даних банківської картки).
Захист CSRF також означає захист від XSS
Навіть якщо анти-CSRF токени налаштовані правильно, наявність вразливості XSS (або інших недоліків) у вебдодатку може обійти ці захисти.
Наприклад, зловмисник може використовувати міжсайтовий скриптинг (XSS) для запуску скрипту, який непомітно отримує нову версію форми разом із поточним (дійсним) токеном, що дозволяє йому виконувати CSRF для цієї сесії користувача.
Виявлення вразливостей у вебдодатках, зокрема CSRF та XSS
Незалежно від того, чи впроваджено анти-CSRF токени, найкращою практикою є тестування безпеки вебсайту, аби знайти його вразливості, в тому числі CSRF і XSS.
Що можна використовувати:
- Динамічне тестування безпеки додатків (DAST, наприклад, Invicti на основі Netsparker та Acunetix): не потребує вихідного коду і дозволяє перевірити вебсайт під час його виконання, надаючи максимально реалістичну картину поточного стану безпеки.
- Статичне тестування безпеки додатків (SAST, як-от Mend.io): використовується під час розробки вебзастосунків, дозволяючи перевіряти стан безпеки ще з ранніх стадій проєкту.
Найкращою практикою є поєднання цих методів, адже SAST не може виявити вразливості під час виконання програми, а DAST не може просканувати всю базу коду за потреби та бути впровадженим на дуже ранніх стадіях розробки.
Ви можете безкоштовно протестувати рішення Invicti (DAST, IAST) з технологією автоматичного підтвердження вразливостей, а також продукт Mend.io (SAST, SCA, безпека контейнерів), що відрізняється швидкістю і потужністю двигуна сканування.
Для цього, будь ласка, залиште ваші контактні дані у формі нижче:







