Розуміння маркера автентичності Rails


982

Я стикаюся з деякими проблемами щодо токена автентичності в Rails, як це я вже багато разів.

Але я дійсно не хочу просто вирішувати цю проблему і продовжувати. Я дуже хотів би зрозуміти маркер автентичності. Ну, моє запитання: чи є у вас якесь повне джерело інформації на цю тему чи ви витратили свій час на детальне пояснення тут?


7
Також дивіться: "Чому Google надає час (1) на їх відповідь JSON?" stackoverflow.com/questions/2669690/…
Хлоя

Відповіді:


1462

Що сталося

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

Чому це трапляється

Оскільки маркер автентичності зберігається в сеансі, клієнт не може знати його значення. Це заважає людям подавати форми в додаток Rails, не переглядаючи форму в самій програмі. Уявіть, що ви користуєтесь послугою A, ви ввійшли в службу і все нормально. Тепер уявіть, що ви пішли користуватися послугою B, і побачили вподобане вам зображення, і натиснули на зображення, щоб переглянути його більший розмір. Тепер, якщо на службі B був якийсь злий код, він може надіслати запит до служби A (на яку ви ввійшли в систему) та попросити видалити ваш рахунок, надіславши запит на адресу http://serviceA.com/close_account. Це те, що відомо під назвою CSRF (підробка між запитами на сайті) .

Якщо служба A використовує маркери автентичності, цей вектор атаки більше не застосовується, оскільки запит від служби B не міститиме правильного маркера автентичності і не буде дозволено продовжувати.

Документи API описують деталі про метатег:

Захист CSRF увімкнено protect_from_forgeryметодом, який перевіряє маркер і скидає сеанс, якщо він не відповідає тому, що очікувалося. Виклик цього методу створюється для нових програм Rails за замовчуванням. Параметр токена названо authenticity_tokenза замовчуванням. Ім’я та значення цього маркера слід додавати до кожного макета, який надає форми, включаючи csrf_meta_tagsв голову HTML.

Примітки

Майте на увазі, Rails перевіряє лише невластиві методи (POST, PUT / PATCH та DELETE). GET-запит не перевіряється на маркування автентичності. Чому? оскільки специфікація HTTP зазначає, що GET-запити є ідентичними, і не повинні створювати, змінювати або знищувати ресурси на сервері, а запит повинен бути idempotent (якщо ви будете виконувати одну і ту ж команду кілька разів, ви повинні отримувати однаковий результат кожен раз).

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

Уроки

Використовуйте authenticity_tokenдля захисту своїх невластивих методів (POST, PUT / PATCH і DELETE). Також не забудьте дозволити будь-які запити GET, які потенційно могли б змінити ресурси на сервері.


РЕДАКТУВАННЯ : Перевірте коментар @erturne щодо того, що GET-запити є ідентичними . Він пояснює це кращим чином, ніж я робив тут.


25
@Faisal, чи можливо тоді зловмисник просто прочитати / захопити "прихований" елемент форми для служби A і отримати той унікальний маркер, згенерований для користувача - враховуючи, що він отримав доступ до сеансу, розпочатого користувачем для служби A?
marcamillion

11
@marcamillion: Якщо хтось захопив ваш сеанс під час обслуговування A, то марка автентичності не захистить вас. Викрадач зможе подати запит, і це буде дозволено продовжувати.
Файсал

12
@zabba: Rails підвищує виняток ActionController :: InvalidAuthenticityToken, якщо форма подається без належного маркера. Ви можете рятувати_виключення та виконувати будь-яку обробку.
Файсал

5
re "Також переконайтеся, що не робити жодних GET-запитів, які потенційно можуть змінювати ресурси на сервері." - це включає не використання match () у маршрутах, які потенційно можуть дозволити GET запити до контролерів дій, призначених для отримання лише постів POST
Steven Soroka

102
"... і запит повинен бути ідентичним (якщо ви будете виконувати одну і ту ж команду кілька разів, ви повинні отримувати однаковий результат кожен раз)." Тут лише тонке уточнення. Безпечний означає відсутність побічних ефектів. Idempotent означає той же побічний ефект, незалежно від того, скільки разів викликається послуга. Усі безпечні послуги за своєю суттю ідентичні, оскільки немає побічних ефектів. Виклик GET на ресурсі поточного часу кілька разів повертає різний результат щоразу, але це безпечно (і, таким чином, безвідмовно).
erturne

137

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

Якщо у вас просто виникають труднощі з рейками, забороняючи доступ до сценарію AJAX, ви можете скористатися цим

<%= form_authenticity_token %>

щоб створити правильний маркер під час створення форми.

Детальніше про це ви можете прочитати в документації .


88

Що таке CSRF?

Маркер автентичності є контрзаходом для підробки підписів на веб-сайті (CSRF). Що таке CSRF, запитаєте ви?

Це зловмисник, який може потенційно захопити сеанси, навіть не знаючи жетонів сеансу.

Сценарій :

  • Відвідайте сайт свого банку, увійдіть у систему.
  • Потім завітайте на сайт зловмисника (наприклад, рекламоване оголошення від ненадійної організації).
  • Сторінка зловмисника включає форму з тими ж полями, що і форма банку "Трансфертні кошти".
  • Зловмисник знає інформацію про ваш рахунок та має попередньо заповнені поля форми для переказу грошей з вашого рахунку на рахунок зловмисника.
  • Сторінка зловмисника включає Javascript, який подає форму у ваш банк.
  • Після надсилання форми веб-переглядач включає файли cookie для веб-сайту банку, включаючи маркер сесії.
  • Банк перераховує гроші на рахунок зловмисника.
  • Форма може містити невидимий кадр, якщо ви ніколи не знаєте нападу.
  • Це називається підробка між запитами на сайт (CSRF).

Рішення CSRF :

  • Сервер може відзначати форми, що надійшли від самого сервера
  • Кожна форма повинна містити додатковий маркер автентифікації як приховане поле.
  • Маркер повинен бути непередбачуваним (зловмисник не може здогадатися).
  • Сервер надає дійсний маркер у формах на своїх сторінках.
  • Сервер перевіряє маркер, коли форма розміщена, відхиляє форми без належного маркера.
  • Приклад маркера: ідентифікатор сеансу зашифрований секретним ключем сервера.
  • Rails автоматично генерує такі маркери: дивіться поле введення автентичності_token у будь-якій формі.

1
Ось варіант цього ж пояснення , що є менш точним , але і менш абстрактні: stackoverflow.com/a/33829607/2810305
Lutz Prechelt

Я не впевнений, але чи дозволяють сучасні браузери надсилати неідентичні запити (POST / PUT / DELETE) на інший домен? Гадаю, в самих браузерах має бути захист від таких
divideByZero

45

Приклад мінімальної атаки, яку можна було б запобігти: CSRF

На своєму веб-сайті evil.comя переконую вас надіслати таку форму:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="to"      value="ciro"></p>
  <p><input type="hidden" name="ammount" value="100"></p>
  <p><button type="submit">CLICK TO GET PRIZE!!!</button></p>
</form>

Якщо ви ввійдете в свій банк через сесійні файли cookie, файли cookie будуть надіслані, а переказ буде здійснено без того, щоб ви цього навіть знали.

Тобто, грає маркер CSRF:

  • з відповіддю GET, що повернув форму, Rails надсилає дуже довгий випадковий прихований параметр
  • коли браузер робить POST-запит, він відправить параметр разом, і сервер прийме його лише у тому випадку, якщо він відповідає

Так форма в автентичному браузері виглядала б так:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="authenticity_token" value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
  <p><input type="hidden" name="to"                 value="ciro"></p>
  <p><input type="hidden" name="ammount"            value="100"></p>
  <p><button type="submit">Send 100$ to Ciro.</button></p>
</form>

Таким чином, моя атака буде невдалою, оскільки вона не надсилає authenticity_tokenпараметр, і я не можу здогадатися, оскільки це величезна випадкова кількість.

Ця методика профілактики називається схемою маркера синхронізатора .

Однакова політика щодо походження

Але що робити, якщо зловмисник зробив два запити з JavaScript, один для читання маркера, а другий для здійснення передачі?

Шаблону жетонів синхронізатора тільки для цього недостатньо!

Тут на допомогу приходить політика того самого походження, як я пояснив на веб- сайті: /security/8264/why-is-the-same-origin-policy-so-important/72569# 72569

Як Рейли надсилає жетони

Охоплено за адресою: Рейки: Як працює csrf_meta_tag?

В основному:

  • Помічники HTML, наприклад, form_tagдодають приховане поле до форми, якщо це не форма GET

  • AJAX автоматично обробляється jquery-ujs , який зчитує маркер з metaелементів, доданих до вашого заголовка csrf_meta_tags(присутній у шаблоні за замовчуванням) та додає його до будь-якого запиту.

    uJS також намагається оновити маркер у формах у застарілих кешованих фрагментах.

Інші підходи до профілактики


Дякую, але ваша думка про те, що покладатися на ту саму політику щодо джерела, що не зможете спочатку просто прочитати маркер CSRF, здається, помилковою. Отже, спочатку ви говорите, що ви можете розмістити POST на інше походження, але не вмієте читати з нього, здається дивним, але я думаю, що це правильно, але ви можете ввести тег зображення або сценарію з доступом до сторінки та зв’язати обробник для аналізу відповіді і отримати так?
bjm88

@ bjm88 вводить сценарій куди? На вашому сайті чи на атакованому сайті? Якщо нападає сайт, дозвіл на введення скриптів є добре відомим недоліком безпеки, і він фактично заставляє веб-сайт. Кожен веб-сайт повинен боротися з ним за допомогою санітарних даних. Для зображень я не бачу, як їх можна використовувати для нападу. На веб-сайті, що атакує: ви можете змінити веб-переглядач, щоб він міг читати, і, таким чином, автоматично пішати пішки :-), але пристойні браузери заважають це за замовчуванням, спробуйте.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

43

Маркер автентичності використовується для запобігання атак на підписи між веб-сайтами (CSRF). Щоб зрозуміти маркер автентичності, спочатку слід зрозуміти атаки CSRF.

КСРР

Припустимо, ви є автором bank.com. На вашому веб-сайті є форма, яка використовується для переказу грошей на інший рахунок із GET-запитом:

введіть тут опис зображення

Хакер міг просто надіслати сервер запит HTTP, кажучи GET /transfer?amount=$1000000&account-to=999999, правда?

введіть тут опис зображення

Неправильно. Атака хакерів не спрацює. Сервер в основному буде думати?

Так? Хто цей хлопець, намагається ініціювати передачу. Це не власник облікового запису, це точно.

Як сервер це знає? Тому що немає session_idфайлу cookie, що засвідчує запитувач.

Коли ви входите із своїм іменем користувача та паролем, сервер встановлює session_idфайл cookie у вашому браузері. Таким чином, вам не потрібно автентифікувати кожен запит своїм іменем користувача та паролем. Коли ваш браузер надсилає session_idфайли cookie, сервер знає:

О, це Джон Доу. Він зареєструвався успішно 2,5 хвилини тому. Йому добре йти.

Хакер може подумати:

Хм. Звичайний HTTP-запит не працюватиме, але якби я міг отримати руку на цьому session_idфайлі cookie, я був би золотим.

У браузері користувачів встановлено купу файлів cookie для bank.comдомену. Кожен раз, коли користувач робить запит до bank.comдомену, всі файли cookie надсилаються разом. Включаючи session_idпечиво.

Тож якщо хакер може змусити вас зробити заявку GET, яка перераховує гроші на його рахунок, він буде успішним. Як він міг вас обдурити в цьому? Завдяки підробці запиту на веб-сайті.

Насправді це досить просто. Хакер міг просто змусити вас відвідати його веб-сайт. На своєму веб-сайті він може мати такий тег зображення:

<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">

Коли користувач переглядає цей тег зображень, він надсилає GET-запит до цієї URL-адреси. А оскільки запит надходить від його браузера, він надсилає разом із ним усі файли cookie, пов’язані з bank.com. Якщо користувач нещодавно ввійшов у bank.com... session_idcookie буде встановлено, і сервер подумає, що користувач мав намір перерахувати $ 1 000 000 на рахунок 999999!

введіть тут опис зображення

Ну, просто не відвідуйте небезпечні сайти, і ви будете добре.

Цього недостатньо. Що робити, якщо хтось розмістить це зображення у Facebook і воно з’явиться на вашій стіні? Що робити, якщо він вводиться на сайт, який ви відвідуєте, при нападі XSS?

Це не так вже й погано. Вразливі лише запити GET.

Неправда. Форма, яка надсилає POST-запит, може динамічно генеруватися. Ось приклад з Посібника з безпеки по Rails :

<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>

Маркер автентичності

Коли у вас ApplicationControllerце є:

protect_from_forgery with: :exception

Це:

<%= form_tag do %>
  Form contents
<% end %>

Складається в це:

<form accept-charset="UTF-8" action="/" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
  Form contents
</form>

Зокрема, створюється таке:

<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />

Для захисту від атак CSRF, якщо Rails не бачить маркер автентичності, надісланий разом із запитом, він не вважатиме запит безпечним.

Як нападник повинен знати, що це маркер? Різне значення генерується випадковим чином кожного разу, коли формується форма:

введіть тут опис зображення

Напад крос-скриптів (XSS) - ось як. Але це різна вразливість для іншого дня.


39

Метод Authenticity Tokenrails - це запобігання атакам підробок між сайтом (CSRF або XSRF) .

Простіше кажучи, це гарантує, що запити PUT / POST / DELETE (методи, які можуть змінювати контент) до вашого веб-додатку здійснюються з браузера клієнта, а не від сторонньої сторони (зловмисника), який має доступ до створеного файлу cookie на стороні клієнта.


34

оскільки Authenticity Tokenце так важливо, і в Rails 3.0+ ви можете використовувати

 <%= token_tag nil %>

створити

<input name="authenticity_token" type="hidden" value="token_value">

де завгодно


Це мені було корисно. Насправді я намагався зробити це XSSна сторінці входу, не для шахрайських цілей, а щоб створити новий сеанс із попередньо заповненим іменем користувача. Тепер я знаю, що можу просто використовувати value="token_value".
Майкл - Де Clay Shirky

27

Обережно, механізм Token Authenticity може призвести до перегонів, якщо у вас є кілька одночасних запитів від одного клієнта. У цій ситуації ваш сервер може генерувати декілька маркерів автентичності, коли має бути лише один, а клієнт, який отримає попередній маркер у формі, відмовиться від наступного запиту, оскільки маркер cookie сеансу був перезаписаний. Тут написано цю проблему і не зовсім тривіальне рішення тут: http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sesions-and-how-to-fix-them/


11

Методи, де authenticity_tokenце потрібно

authenticity_token потрібен у випадку ідентичних методів, таких як розміщення, видалення та видалення, оскільки Idempotent методи впливають на дані.

Чому це потрібно

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


3
Насправді, чи не навпаки? GET є idempotent, оскільки його виклик не повинен змінювати стан системи, де дієслова PUT POST та DELETE НЕ є ідентичними дієсловами, оскільки вони змінюють стан системи. IE: authentication_token потрібен у випадку НЕ ідентичних методів.
Жан-Тео

2
@ Jean-Daube, uma: idempotent означає, що якщо зробити двічі, дія відбувається лише один раз. GET, PUT і DELETE є idempotent : w3.org/Protocols/rfc2616/rfc2616-sec9.html Ключовою властивістю тут є не idempotency, але якщо метод змінює чи не дані, що називається "Безпечний метод" чи ні.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

6

Що таке аутентифікація_токен?

Це випадковий рядок, який використовується програмою rails, щоб переконатися, що користувач запитує або виконує дію зі сторінки програми, а не з іншого додатка чи сайту.

Чому потрібна автентифікація_токен?

Щоб захистити ваш додаток або сайт від підробки між веб-сайтами.

Як додати до форми автентифікацію_токена?

Якщо ви генеруєте форму за допомогою тегу form_for, автентифікація_token автоматично додається ще, що ви можете використовувати <%= csrf_meta_tag %>.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.