Я пишу заявку (Django, так трапляється) і просто хочу уявити, що насправді є "токеном CSRF" і як він захищає дані. Чи не є безпечними дані публікації, якщо ви не використовуєте маркери CSRF?
Я пишу заявку (Django, так трапляється) і просто хочу уявити, що насправді є "токеном CSRF" і як він захищає дані. Чи не є безпечними дані публікації, якщо ви не використовуєте маркери 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 з іншого веб-сайту.
www.cute-cat-pictures.org
звичайно не має доступу до вашого маркера анти-CSRF www.mybank.com
через контроль доступу HTTP. Ця примітка важлива для деяких людей, які безпідставно надсилають заголовок Access-Control-Allow-Origin: *
для кожної відповіді веб-сайту, не знаючи, для чого це потрібно, лише тому, що вони не можуть використовувати API з іншого веб-сайту.
Так, дані публікації є безпечними. Але походження цих даних немає. Таким чином хтось може обманути користувача з JS увійти на ваш сайт, переглядаючи веб-сторінку зловмисника.
Щоб запобігти цьому, django надсилатиме випадковий ключ як у файлі cookie, так і у формі даних. Потім, коли користувачі розміщують пошту, він перевірить, чи однакові два ключі. У випадку, коли користувач обдурить, сторонній веб-сайт не може отримати файли cookie вашого сайту, тим самим спричиняючи помилку авторизації.
Сайт створює унікальний маркер, коли робить сторінку форми. Цей маркер необхідний для публікації / повернення даних на сервер.
Оскільки маркер генерується на вашому веб-сайті та надається лише тоді, коли генерується сторінка із формою, деякі інші сайти не можуть імітувати ваші форми - вони не матимуть маркер і тому не можуть розміщувати на вашому сайті.
У блозі 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, інший - перевірка заголовка реферала.