ruby-on-rails - react - ruby on rails token




Понимание идентификатора подлинности Rails (7)

Что такое CSRF?

Идентификатор подлинности является контрмерой для подпрограммы подбора сайтов (CSRF). Что такое CSRF, спросите вы?

Это способ, которым атакующий может потенциально захватывать сеансы, даже не зная токенов сеанса.

Сценарий :

  • Посетите сайт своего банка, войдите в систему.
  • Затем посетите сайт злоумышленника (например, рекламное объявление от ненадежной организации).
  • Страница Attacker включает форму с теми же полями, что и форма «Transfer Funds» банка.
  • Атакующий знает вашу учетную запись и имеет предварительно заполненные поля формы, чтобы переводить деньги со своего аккаунта на счет злоумышленника.
  • Страница атакующего включает Javascript, который отправляет форму в ваш банк.
  • Когда форма отправляется, браузер включает ваши файлы cookie для сайта банка, включая токен сеанса.
  • Банк переводит деньги на счет злоумышленника.
  • Форма может быть в iframe, которая невидима, поэтому вы никогда не знаете, что произошло.
  • Это называется Cross-Site Request Forgery (CSRF).

CSRF-раствор :

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

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

Но я действительно не хочу просто решать эту проблему и продолжать. Мне бы очень хотелось понять токен аутентичности. Ну, на мой вопрос: есть ли у вас какой-то полный источник информации по этому вопросу или вы проводите время, чтобы подробно объяснить здесь?


Маркер аутентификации используется для предотвращения атак типа Cross-Site Request Forgery (CSRF). Чтобы понять токен аутентичности, вы должны сначала понять атаки CSRF.

CSRF

Предположим, что вы являетесь автором bank.com . На вашем сайте есть форма, используемая для перевода денег на другую учетную запись с запросом GET:

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

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

А? Кто этот парень пытается начать передачу. Это не владелец учетной записи, это точно.

Как сервер знает об этом? Потому что cookie session_id не аутентифицирует запросчика.

Когда вы входите в систему с вашим именем пользователя и паролем, сервер устанавливает cookie session_id в вашем браузере. Таким образом, вам не нужно аутентифицировать каждый запрос с вашим именем пользователя и паролем. Когда ваш браузер отправляет cookie session_id , сервер знает:

О, это Джон Доу. Он подписал контракт успешно 2,5 минуты назад. Он хорош.

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

Хм. Обычный HTTP-запрос не будет работать, но если бы я мог получить свою руку от этого cookie session_id , я был бы золотым.

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

Поэтому, если хакер может заставить вас сделать запрос GET, который переводит деньги на его счет, он будет успешным. Как он мог обмануть вас в этом? С перекрестным запросом.

На самом деле это довольно просто. Хакер мог просто заставить вас посетить его сайт. На его веб-сайте у него может быть следующий тег изображения:

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

Когда браузер пользователей встретит этот тег изображения, он будет делать запрос GET на этот URL-адрес. И поскольку запрос поступает из его браузера, он отправит вместе с ним все файлы cookie, связанные с bank.com . Если пользователь недавно bank.com на bank.com ... будет установлен session_id cookie, и сервер подумает, что пользователь должен перечислить 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 не видит токен аутентификации, отправленный вместе с запросом, он не будет считать запрос безопасным.

Как злоумышленник должен знать, что это за токен? Другое значение генерируется случайным образом каждый раз, когда формируется форма:

Атака Cross Site Scripting (XSS) - вот как. Но это другая уязвимость для другого дня.


Токен подлинности разработан так, что вы знаете, что ваша форма отправляется с вашего сайта. Он создается на машине, на которой он работает, с уникальным идентификатором, который может знать только ваш компьютер, тем самым помогая предотвращать атаки поддельных запросов на подделку.

Если вы просто испытываете трудности с рельсами, лишающими доступ к скрипту AJAX, вы можете использовать

<%= form_authenticity_token %>

для создания правильного токена при создании вашей формы.

Подробнее об этом можно прочитать в documentation .


поскольку Authenticity Token так важен, а в Rails 3.0+ вы можете использовать

 <%= token_tag nil %>

создавать

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

в любом месте


Методы Где требуется authenticity_token

authenticity_token требуется в случае идемпотентных методов, таких как post, put и delete, потому что методы Idempotent влияют на данные.

Почему это необходимо

Это необходимо для предотвращения злых действий. authenticity_token хранится в сеансе, всякий раз, когда на веб-страницах создается форма для создания или обновления ресурсов, то токен аутентификации хранится в скрытом поле и отправляется с формой на сервер. Перед выполнением действия пользователь отправил authenticity_token, перекрестие проверено с помощью authenticity_token хранящегося в сеансе. Если authenticity_token тот же, то процесс продолжается, иначе он не будет выполнять действия.


Пример минимальной атаки, который будет предотвращен

На моем сайте evil.com я 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 , и я никак не мог догадаться, так как это огромное случайное число.

Этот метод профилактики называется Synchronizer Token Pattern .

Шаблон маркера синхронизатора работает из-за той же политики происхождения : если я могу сделать запрос XHR GET в ваш банк с evil.com и прочитать результат, я бы смог просто прочитать токен, а затем сделать запрос позже. Я объяснил это далее: https://security.stackexchange.com/a/72569/53321

Я настоятельно рекомендую вам прочитать руководство OWASP по этому и любому другому вопросу безопасности.

Как Rails отправляет токены

Покрытие: Rails: Как работает csrf_meta_tag?

В принципе:

  • HTML-помощники, такие как form_tag добавляют вам скрытое поле в форму, если это не форма GET

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

    uJS также пытается обновить токен в формах устаревших кешированных фрагментов.

Другие методы профилактики


Что такое authentication_token?

Это случайная строка, используемая приложением rails, чтобы убедиться, что пользователь запрашивает или выполняет действие со страницы приложения, а не из другого приложения или сайта.

Зачем нужна проверка подлинности?

Чтобы защитить ваше приложение или сайт от подделки запроса на межсайтовый сайт.

Как добавить authentication_token в форму?

Если вы генерируете форму с использованием тега form_for, то автоматически добавляется идентификатор_имя_настройки, иначе вы можете использовать <%= csrf_meta_tag %> .





authenticity-token