Що таке маркер CSRF? Яке його значення і як це працює?


628

Я пишу заявку (Django, так трапляється) і просто хочу уявити, що насправді є "токеном CSRF" і як він захищає дані. Чи не є безпечними дані публікації, якщо ви не використовуєте маркери CSRF?


13
Це секретний, специфічний для користувача маркер у всіх поданих формах та URL-адресах з побічними ефектами, щоб запобігти підпискам між сайтом. Більше інформації тут: en.wikipedia.org/wiki/Cross-site_request_forgery
Роберт Харві

1
здається, що між захистом питання і забороною його бути занадто широким є
межа

2
З оглядового листа щодо запобігання підробці запитів на міжміські сайти (CSRF) : " Сценарії між веб-сайтами не потрібні, щоб CSRF працював. Однак будь-яка вразливість сценаріїв міжсайтових сценаріїв може бути використана для перемоги над усіма методами пом'якшення наслідків CSRF [...]. Це тому, що корисне навантаження XSS може просто прочитати будь-яку сторінку на сайті за допомогою XMLHttpRequest [...]. Обов'язково не існує вразливості XSS для того, щоб захист CSRF не вдалося обійти. "
toraritte

Відповіді:


1497

Підробка міжміських запитів (CSRF) простими словами

  • Припустимо, ви зараз увійшли у свій інтернет-банкінг за адресою www.mybank.com
  • Припустимо, що переказ грошей з боку mybank.comпризведе до запиту (концептуально) форми http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (Номер вашого облікового запису не потрібен, оскільки він має на увазі ваш логін.)
  • Ви відвідуєте www.cute-cat-pictures.org, не знаючи, що це шкідливий сайт.
  • Якщо власник цього сайту знає форму вищезазначеного запиту (просто!) І правильно здогадається, що ви ввійшли в систему mybank.com(вимагає трохи удачі!), Він може включити на свою сторінку запит на зразок http://www.mybank.com/transfer?to=123456;amount=10000(де 123456номер їх облікового запису на Кайманових островах і 10000це сума, яку ви раніше вважали, що раді мати.)
  • Ви отримали цю www.cute-cat-pictures.orgсторінку, тому ваш веб-переглядач зробить цей запит.
  • Ваш банк не може розпізнати це походження запиту: Ваш веб-браузер надішле запит разом із вашим www.mybank.comфайлом cookie, і це буде виглядати цілком законно. Туди йдуть ваші гроші!

Це світ без маркерів CSRF .

Тепер для кращого з маркерами CSRF :

  • Запит передачі продовжується з третім аргументом: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • Цей маркер - це величезне, неможливо здогадатися випадкове число, яке mybank.comбуде міститись на їхній власній веб-сторінці, коли вони подаватимуть її вам. Це різне щоразу, коли вони кому-небудь подають будь-яку сторінку.
  • Зловмисник не в змозі вгадати маркер, не в змозі переконати ваш веб-браузер здати його (якщо браузер працює правильно ...), і тому зловмисник не зможе створити дійсний запит, оскільки запити з неправильний маркер (або ні маркер) буде відхилено www.mybank.com.

Результат: Ви зберігаєте свої 10000грошові одиниці. Я пропоную вам пожертвувати частиною цього у Вікіпедії.

(Ваш пробіг може відрізнятися.)

Редагувати з коментаря, який варто прочитати:

Варто зауважити, що сценарій із www.cute-cat-pictures.orgзвичайно не має доступу до вашого маркера анти-CSRF www.mybank.comчерез контроль доступу HTTP. Ця примітка важлива для деяких людей, які безпідставно надсилають заголовок Access-Control-Allow-Origin: *для кожної відповіді веб-сайту, не знаючи, для чого це потрібно, лише тому, що вони не можуть використовувати API з іншого веб-сайту.


36
І очевидно, що маркер в ідеалі буде названий токеном anti -CSRF, але ім'я, ймовірно, досить складне, як є.
Lutz Prechelt

3
@LutzPrechelt дякую. Чому javascript не може отримати маркери автентичності у браузері?
BKSpurgeon

72
Варто зауважити, що сценарій із www.cute-cat-pictures.orgзвичайно не має доступу до вашого маркера анти-CSRF www.mybank.comчерез контроль доступу HTTP. Ця примітка важлива для деяких людей, які безпідставно надсилають заголовок Access-Control-Allow-Origin: *для кожної відповіді веб-сайту, не знаючи, для чого це потрібно, лише тому, що вони не можуть використовувати API з іншого веб-сайту.
SOFe

9
@AugustinRiedinger Якщо зловмисник відкриє веб-сторінку на своєму комп’ютері - оскільки у них немає файлу cookie зареєстрованого користувача - він не отримає відповідний маркер csrf (кожен маркер csrf повинен бути дійсним лише для конкретного сеансу користувача). Якщо зловмисник намагається завантажити веб-сторінку, що містить маркер, на комп’ютер користувача, зі скриптом, розміщеним на веб-сайті "cute-cat-pictures", браузер заборонить йому читати www.mybank.com (і маркер) через та сама політика походження.
Марсель

13
@LutzPrechelt Я думаю, що недостатньо того, що маркер завжди різний, він повинен з'єднуватися з сеансом, і сервер повинен перевірити, що маркер, який він отримує, генерується для сеансу, який сервер ідентифікує за отриманим файлом cookie. В іншому випадку хакер може просто відвідати мій банк і отримати дійсний маркер. Отже, якщо ви використовуєте новий маркер у будь-якій формі, вам потрібно зберегти його в парі з sessionid на сервері. Можливо, простіше використовувати один і той же маркер за сеанс.
Марсель

222

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

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


@DmitryShevchenko Привіт, намагаюся зрозуміти, чим відрізняється цей спосіб cookie + form-input від просто перевірки реферала на стороні сервера? Усі приклади, які я знаходжу, пов’язані з хакером, який обманює користувача, щоб публікувати його зі свого сайту на фактичний сайт.
Етан

Гаразд, я з’ясував, чому референт не використовується. У багатьох випадках він блокується, оскільки іноді вважається, що він зберігає конфіденційну інформацію. Корпоративні компанії та їхні довіреники зазвичай роблять це. Однак якщо використовується HTTPS, є більша ймовірність, що він не буде заблокований.
Етан

4
Зміна реферала легко змінити, я б не сказав, що це достовірна інформація. Однак маркер CSRF генерується за допомогою секретного ключа сервера і зазвичай прив’язується до користувача
Дмитро Шевченко

1
Я не дуже розумію, чому це загроза безпеці. Користувач увійде на інший сайт ... але оригінальний сайт не зможе отримати цю інформацію. Правильно?
Аакіл Фернандес

6
Ну, припустимо, я ввожу зловмисний кадр " bank.com/transfer?from=x&to=y " у, скажімо, Facebook.com. Якщо ви є клієнтом bank.com і ви переходите на Facebook, цей iframe завантажить банківську сторінку з вашими файлами cookie (оскільки браузер надсилатиме їх на відомий домен) і здійснюватиме переказ грошей. Не знаючи нічого.
Дмитро Шевченко

74

Сайт створює унікальний маркер, коли робить сторінку форми. Цей маркер необхідний для публікації / повернення даних на сервер.

Оскільки маркер генерується на вашому веб-сайті та надається лише тоді, коли генерується сторінка із формою, деякі інші сайти не можуть імітувати ваші форми - вони не матимуть маркер і тому не можуть розміщувати на вашому сайті.


10
Чи може користувач захопити вихідний маркер у джерело, схопити надіслане їм файли cookie, а потім подати на сторонній сайт подачу?
Джек Марчетті

9
@JackMarchetti так. але це буде дорого, оскільки кожного разу, коли ви хочете подати форму з сторонніх сайтів, вам доведеться завантажувати сторінку та аналізувати маркер. Токени CSRF повинні ідеально поєднуватися з іншими формами безпеки, якщо ви переймаєтесь цим вектором нападу
хтоne

4
У мене те саме питання, що і у @JackMarchetti, що не ясно - якщо маркер CSRF змінюється на кожному вході. Якщо він залишається таким же, що заважатиме зловмисникові спочатку ввійти в систему, схопивши маркер запиту, а потім вставивши його в атаку?
Павло Прейбіш

7
@PaulPreibisch він повинен змінюватись на кожному завантаженні сторінки - не на кожному вході. Таким чином зловмисник повинен буде запитувати сторінку щоразу, коли вони хочуть надіслати форму. Це робить набагато складніше.
tkone

9
@tkone, Це насправді не робить це набагато складніше. Якщо просто подвоїти кількість зусиль і часу. Це не додає ніякого виду заборонної обробки. Трюк також полягає в тому, щоб пов’язати маркер CSRF з печивом для певного домену та надіслати це cookie разом із формою. Як файли cookie, так і дані публікації форми повинні бути надіслані серверу на запит POST. Цей спосіб вимагає нападу викрадення файлів cookie, щоб мати змогу наслідувати законний запит.
Педро Кордейро

55

У блозі Cloud Under є гарне пояснення маркерів CSRF.

Уявіть, що у вас був веб-сайт, як спрощений Twitter, розміщений на a.com. Користувачі, які зареєструвались, можуть ввести якийсь текст (твіт) у форму, яка надсилається серверу як POST-запит і публікується, коли вони натискають кнопку "Надіслати". На сервері користувач ідентифікує файл cookie, що містить його унікальний ідентифікатор сесії, тому ваш сервер знає, хто опублікував щебет.

Форма може бути такою ж простою:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

А тепер уявіть, поганий хлопець копіює та вставляє цю форму на свій шкідливий веб-сайт, скажімо, b.com. Форма все одно запрацює. Поки користувач увійшов у ваш Twitter (тобто у нього є дійсне cookie сеансу для a.com), запит POST буде надісланий на http://a.com/tweet та оброблений, як зазвичай, коли користувач натискає кнопку "Надіслати".

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

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

Тепер, якщо хтось із ваших користувачів потрапляє на веб-сайт поганого хлопця і натискає "Клацніть, щоб перемогти!" кнопка, форма надсилається на ваш веб-сайт, користувач правильно ідентифікується ідентифікатором сеансу у файлі cookie та прихований твіт стає опублікованим.

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

Форму можна легко подати звідусіль та звідусіль. Як правило, це загальна особливість, але є набагато більше випадків, коли важливо дозволити надсилати форму лише з домену, де вона належить.

Навіть гірше, якщо веб-додаток не розрізняє POST та GET-запити (наприклад, у PHP, використовуючи $ _REQUEST замість $ _POST). Не робіть цього! Запити на зміну даних можна подати так само просто<img src="http://a.com/tweet?tweet=This+is+really+bad"> , вбудовані на шкідливий веб-сайт або навіть електронний лист.

Як переконатися, що форму можна подати лише з мого власного веб-сайту? Тут надходить маркер CSRF. Маркер CSRF - це випадковий, важко здогадатися рядок. На сторінці із формою, яку ви хочете захистити, сервер генерував би випадкову рядок, маркер CSRF, додав би її до форми як приховане поле, а також запам’ятав її якось, зберігаючи її в сеансі або встановлюючи файл cookie містить значення. Тепер форма виглядатиме так:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

Коли користувач подає форму, сервер повинен просто порівняти значення розміщеного поля csrf-токен (ім'я не має значення) з CSK-маркером, запам'ятовуваним сервером. Якщо обидва рядки рівні, сервер може продовжувати обробляти форму. В іншому випадку сервер повинен негайно припинити обробляти форму і відповісти на помилку.

Чому це працює? Є кілька причин, через які недобрий хлопець з нашого прикладу вище не може отримати маркер CSRF:

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

Оскільки шкідливу сторінку поганого хлопця завантажує браузер вашого користувача з іншого домену (b.com замість a.com), поганий хлопець не має шансу кодувати JavaScript, який завантажує вміст, а отже, і поточний маркер CSRF нашого користувача від твій сайт. Це тому, що веб-браузери за замовчуванням не дозволяють запити міждоменних AJAX.

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

Коли я повинен захиститися від підробки міжпрофільних заявок? Якщо ви можете переконатися, що ви не змішуєте GET, POST та інші методи запиту, як описано вище, гарним початком буде захист усіх запитів POST за замовчуванням.

Вам не потрібно захищати запити PUT і DELETE, оскільки, як пояснено вище, браузер не може надіслати стандартну форму HTML, використовуючи ці методи.

JavaScript з іншого боку дійсно може робити інші типи запитів, наприклад, використовуючи функцію $ .ajax () jQuery, але пам’ятайте, що для запитів AJAX для роботи доменів повинні відповідати (доки ви явно не налаштовуєте веб-сервер інакше) .

Це означає, що часто вам навіть не потрібно додавати маркер CSRF до запитів AJAX, навіть якщо це POST-запити, але вам доведеться переконатися, що ви лише обходите чек CSRF у веб-додатку, якщо запит POST насправді є Запит AJAX Це можна зробити, шукаючи наявність заголовка на зразок X-Requested-With, який зазвичай включає запити AJAX. Ви також можете встановити інший спеціальний заголовок і перевірити його наявність на стороні сервера. Це безпечно, оскільки веб-переглядач не додає власні заголовки до звичайного подання HTML-форми (див. Вище), тому містер Bad Guy не зможе імітувати цю поведінку з формою.

Якщо ви сумніваєтесь у запитах AJAX, оскільки з певних причин ви не можете перевірити такий заголовок, як X-Requested-With, просто передайте згенерований маркер CSRF у свій JavaScript та додайте маркер до запиту AJAX. Існує кілька способів зробити це; або додати його до корисного навантаження так, як звичайна форма HTML, або додати спеціальний заголовок до запиту AJAX. Поки ваш сервер знає, де його шукати у вхідному запиті та зможе порівняти його з початковим значенням, яке воно запам'ятовує під час сеансу чи файлу cookie, ви будете відсортовані.


Дякуємо за детальну інформацію. Під час запиту на пошту сайт має відправити маркер csrf на сервер, тож коли клієнт надішле цей маркер csrf на сервер? Це під час оформлення запиту на параметри передпольоту? Будь ласка, детальніше уточнюйте цю частину ..
Sm Srikanth

@Dan Яким чином b.com може отримати доступ до файлів cookie іншого сайту a.com?
Закира

8

Корінь усього цього полягає в тому, щоб переконатися, що запити надходять від реальних користувачів сайту. Для форм формується маркер csrf і повинен бути прив’язаний до сеансів користувача. Він використовується для надсилання запитів на сервер, в якому маркер їх підтверджує. Це один із способів захисту від csrf, інший - перевірка заголовка реферала.


7
Не покладайтеся на заголовок реферала, його можна легко підробити.
каг

3
Це правильна відповідь! Маркер ОБОВ'ЯЗКОВО прив’язаний до сеансу на сервері. Порівнювати дані Cookie + Form, як-от найвідповідальніша відповідь, абсолютно неправильно. Обидва компоненти складають частину запиту, який формує клієнт.
Лі Девіс

3
Власне, ні. Маркер ОБОВ'ЯЗКОВО прив’язаний до кожного ЗАПИТУВАННЯ до Сервера. Якщо ви прив'язуєте його лише до сеансу, ви ризикуєте, що хтось вкраде маркер сеансу та надішле запит із цим маркером. Тому для максимальної безпеки маркер повинен бути прив’язаний до кожного запиту http.
chrisl08
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.