Понимание токена подлинности Rails - PullRequest
938 голосов
/ 03 июня 2009

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

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

Ответы [ 10 ]

1417 голосов
/ 15 октября 2009

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

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

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

Уроки

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


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

131 голосов
/ 03 июня 2009

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

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

<%= form_authenticity_token %>

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

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

81 голосов
/ 13 июня 2012

Что такое CSRF?

Маркер подлинности является контрмерой для подделки межсайтовых запросов (CSRF). Вы спрашиваете, что такое CSRF?

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

Сценарий

  • Посетите сайт вашего банка, войдите в систему.
  • Затем посетите сайт злоумышленника (например, рекламное объявление от ненадежной организации).
  • На странице злоумышленника есть форма с теми же полями, что и у банковской формы "Перевод средств".
  • Атакующий знает данные вашей учетной записи и имеет предварительно заполненные поля формы для перевода денег с вашей учетной записи на учетную запись злоумышленника.
  • На странице злоумышленника есть Javascript, который отправляет форму в ваш банк.
  • Когда форма отправляется, браузер включает ваши куки для сайта банка, включая токен сеанса.
  • Банк переводит деньги на счет злоумышленника.
  • Форма может находиться в невидимом фрейме, поэтому вы никогда не узнаете, что атака произошла.
  • Это называется подделкой межсайтовых запросов (CSRF).

CSRF решение :

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

Пример минимальной атаки, которую можно предотвратить

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

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

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

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

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

Covered at: Rails: как работает csrf_meta_tag?

В основном:

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

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

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

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

36 голосов
/ 03 июня 2009

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

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

35 голосов
/ 14 апреля 2017

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

CSRF

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

enter image description here

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

enter image description here

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

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

Откуда сервер знает это? Поскольку session_id cookie не аутентифицирует запрашивающую сторону.

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

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

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

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

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

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

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

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

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

32 голосов
/ 01 августа 2012

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

 <%= token_tag nil %>

для создания

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

везде

25 голосов
/ 31 августа 2011

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

8 голосов
/ 26 февраля 2014

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

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

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

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

3 голосов
/ 22 июля 2016

Что такое маркер аутентификации?

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

Зачем нужен аутентификационный токен?

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

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

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

...