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

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

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

Ответ 1

Что просходит

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

Почему так происходит

Поскольку токен аутентификации хранится в сеансе, клиент не может знать его значение. Это не позволяет людям отправлять формы в приложение Rails, не просматривая форму в самом приложении. Представьте, что вы используете сервис A, вы вошли в сервис и все в порядке. Теперь представьте, что вы пошли пользоваться услугой B, увидели понравившуюся вам картинку и нажали на нее, чтобы просмотреть ее в большем размере. Теперь, если какой-то злой код был в службе B, он мог бы отправить запрос в службу A (в которую вы вошли) и попросить удалить вашу учетную запись, отправив запрос на http://serviceA.com/close_account. Это то, что известно как CSRF (Подделка межсайтовых запросов).

Если служба A использует маркеры подлинности, этот вектор атаки больше не применяется, поскольку запрос от службы B не будет содержать правильный токен подлинности и не будет допущен к продолжению.

Документация API описывает подробности о метатеге:

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

Заметки

Имейте в виду, что Rails проверяет только не идемпотентные методы (POST, PUT/PATCH и DELETE). GET-запрос не проверяется на подлинность токена. Зачем? поскольку в спецификации HTTP говорится, что запросы GET являются идемпотентными и не должны создавать, изменять или уничтожать ресурсы на сервере, а запрос должен быть идемпотентным (если вы выполняете одну и ту же команду несколько раз, вы должны получать один и тот же результат каждый раз).

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

занятия

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


РЕДАКТИРОВАТЬ: Проверьте комментарий @erturne относительно GET-запросов, являющихся идемпотентными. Он объясняет это лучше, чем я здесь.

Ответ 2

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

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

<%= form_authenticity_token %>

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

Подробнее об этом можно узнать в документации.

Ответ 3

Что такое CSRF?

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

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

Сценарий

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

Решение CSRF:

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

Ответ 4

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

Этот метод предотвращения называется шаблоном синхронизатора.

Шаблон токена синхронизатора работает из-за единой политики происхождения: если бы я мог сделать запрос 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 также пытается обновить токен в формах в устаревших кэшированных фрагментах.

Другие профилактические подходы

Ответ 5

Authenticity Token - метод рельсов prevent ' атаки на межсайтовый запрос (CSRF или XSRF).

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

Ответ 6

Маркер подлинности используется для предотвращения атак подделки межсайтовых запросов (CSRF). Чтобы понять маркер подлинности, вы должны сначала понять атаки CSRF.

CSRF

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

enter image description here

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

enter image description here

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

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

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

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

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

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

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

В браузере пользователей есть набор файлов 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 на bank.com... будет установлен cookie session_id, и сервер подумает, что пользователь намеревался перевести $ 1 000 000 на счет 999999!

enter image description here

Ну, просто не посещайте опасные сайты, и все будет в порядке.

Этого недостаточно. Что если кто-то разместит это изображение на Facebook, и оно появится на вашей стене? Что если он внедряется в сайт, который вы посещаете, с атакой XSS?

Это не так плохо. Только GET-запросы уязвимы.

Не правда. Форма, отправляющая запрос POST, может генерироваться динамически. Вот пример из Rails Guide по безопасности:

<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 не увидит токен аутентификации, отправленный вместе с запросом, он не будет считать запрос безопасным.

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

enter image description here

Атака межсайтового скриптинга (XSS) - вот как. Но это другая уязвимость для другого дня.

Ответ 7

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

 <%= token_tag nil %>

создать

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

в любом месте

Ответ 8

Остерегайтесь механизма аутентификации подлинности может привести к условиям гонки, если у вас есть несколько одновременных запросов от одного и того же клиента. В этой ситуации ваш сервер может генерировать несколько токенов аутентификации, когда их должно быть только одно, а клиент, получающий более ранний токен в форме, не сможет выполнить следующий запрос, потому что токен сеанса cookie был перезаписан. Здесь написана запись и это не совсем тривиальное решение: http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/

Ответ 9

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

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

Зачем требуется

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

Ответ 10

Что такое authentication_token?

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

Почему требуется аутентификация_token?

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

Как добавить аутентификацию_token в форму?

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