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


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

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

10 888

10 ответов:

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

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

почему это происходит

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

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

API docs описывает детали о метатеге:

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

Примечания

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

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

уроки

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


EDIT: Регистрация комментарий @erturne что касается запросов GET, являющихся идемпотентными. Он объясняет это лучше, чем я здесь.

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

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

<%= form_authenticity_token %>

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

вы можете подробнее об этом читайте в документация.

Что такое CSRF?

маркер подлинности является контрмерой для подделки межсайтовых запросов (CSRF). Что такое КСРФ, спросите вы?

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

сценарий:

  • посетите сайт вашего банка, войдите в систему.
  • затем посетите сайт злоумышленника (например, спонсируемое объявление от ненадежной организации).
  • страница злоумышленника включает форму с теми же полями, что и форма банка "Перевод средств".
  • злоумышленник знает ваши регистрационные данные, и предварительно заполненные поля формы для перевода денег с вашего счета на счет злоумышленника.
  • страница злоумышленника включает Javascript, который отправляет форму в ваш банк.
  • когда форма будет отправлена, браузер включает ваши куки для сайта банка, включая токен сеанса.
  • банк переводит деньги злоумышленнику счет.
  • форма может быть в iframe, который невидим, так что вы никогда не знаю, что произошло нападение.
  • это называется подделкой межсайтового запроса (CSRF).

CSRF в решение:

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

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

мой сайт 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>

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

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

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

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

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

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

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

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

 <%= token_tag nil %>

создать

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

в любом месте

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

CSRF

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

enter image description here

хакер может просто отправить HTTP-запрос на сервер говорю GET /transfer?amount=00000&account-to=999999, да?

enter image description here

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

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

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

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

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

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

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

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

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

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

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

когда браузер пользователей сталкивается с этим тегом изображения, он будет делать запрос GET на этот url. И поскольку запрос поступает из его браузера, он отправит с ним все куки, связанные с bank.com. Если пользователь недавно вошел в bank.com... элемент session_id cookie будет установлен, и сервер будет думать, что пользователь намеревался передать $1,000,000 на счет 999999!

enter image description here

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

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

это не так уж плохо. Уязвимы только запросы GET.

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

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

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

enter image description here

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

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

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

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

почему это требуется

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

Что такое authentication_token ?

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

зачем нужен authentication_token ?

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

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

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