Я сталкиваюсь с некоторыми проблемами, касающимися токена аутентификации в Rails, поскольку я уже много раз.
Но я действительно не хочу просто решать эту проблему и продолжать. Мне бы очень хотелось понять токен аутентичности. Ну, на мой вопрос: у вас есть какой-то полный источник информации по этому вопросу или вы потратите свое время, чтобы объяснить здесь подробнее?
Когда пользователь просматривает форму для создания, обновления или уничтожения ресурса, приложение Rails создает случайный authenticity_token
, сохраняет этот токен в сеансе и помещает его в скрытое поле в форме. Когда пользователь отправляет форму, Rails ищет authenticity_token
, сравнивает его с тем, который хранится в сеансе, и если они соответствуют запросу, разрешено продолжить.
Поскольку токен аутентичности хранится в сеансе, клиент не может знать его значение. Это не позволяет людям отправлять формы в приложение Rails без просмотра формы внутри этого приложения.
Представьте, что вы используете сервис A, вы вошли в службу, и все в порядке. Теперь представьте, что вы пошли использовать службу B, и вы видели понравившуюся вам картинку, и нажали на картинку, чтобы просмотреть ее более крупный размер. Теперь, если какой-либо злой код был там в службе B, он мог бы отправить запрос на обслуживание A (который вы вошли в систему) и попросить удалить свою учетную запись, отправив запрос на http://serviceA.com/close_account
. Это то, что называется CSRF (Подпрограмма запроса на межсайтовый поиск).
Если служба A использует токены аутентификации, этот вектор атаки больше не применим, так как запрос из службы B не содержит правильный токен аутентификации и не будет разрешен для продолжения.
API docs описывает детали метатега:
Защита 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 являются идемпотентными. Он объясняет это лучше, чем я сделал здесь.
Идентификатор подлинности разработан таким образом, что вы знаете, что ваша форма отправляется с вашего сайта. Он генерируется на машине, на которой он работает, с уникальным идентификатором, который может знать только ваш компьютер, тем самым помогая предотвращать атаки на поддельные запросы на подделку.
Если вы просто испытываете трудности с рельсами, лишающими доступ к AJAX script, вы можете использовать
<%= form_authenticity_token %>
чтобы создать правильный токен при создании вашей формы.
Подробнее об этом можно узнать в документации.
Подлинник аутентификации является контрмерой для подпрограммы подбора сайтов (CSRF). Что такое CSRF, спросите вы?
Это способ, которым злоумышленник может потенциально захватывать сеансы, даже не зная токенов сеанса.
Сценарий
Решение 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 вступает в игру:
Таким образом, форма в аутентичном браузере будет выглядеть так:
<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
, и я никак не мог догадаться, так как это огромное случайное число.
Этот метод профилактики называется Шаблон маркера синхронизатора.
Рисунок токена синхронизатора работает из-за Одинаковая политика происхождения: если бы я мог сделать запрос XET 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 также пытается обновить токен в формах устаревших кешированных фрагментов.
Другие меры профилактики
X-Requested-With
:
Origin
: https://security.stackexchange.com/questions/91165/why-is-the-synchronizer-token-pattern-preferred-over-the-origin-header-check-to Authenticity Token
- метод рельсов prevent ' атаки на межсайтовый запрос (CSRF или XSRF).
Проще говоря, он гарантирует, что запросы PUT/POST/DELETE (методы, которые могут изменять содержимое) в вашем веб-приложении сделаны из клиентского браузера, а не стороннего (злоумышленника), который имеет доступ к cookie, созданный на стороне клиента.
так как Authenticity Token
так важен, а в Rails 3.0+ вы можете использовать
<%= token_tag nil %>
создать
<input name="authenticity_token" type="hidden" value="token_value">
в любом месте
XSS
на странице входа в систему, не для гнусных целей, а для создания нового сеанса с предварительно заполненным именем пользователя. Теперь я знаю, что могу просто использовать value="token_value"
.
Остерегайтесь механизма аутентификации подлинности может привести к условиям гонки, если у вас есть несколько одновременных запросов от одного и того же клиента. В этой ситуации ваш сервер может генерировать несколько токенов аутентификации, когда их должно быть только одно, а клиент, получающий более ранний токен в форме, не сможет выполнить следующий запрос, потому что токен сеанса cookie был перезаписан. Здесь написана запись и это не совсем тривиальное решение: http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
Маркер аутентификации используется для предотвращения атак типа Cross-Site Request Forgery (CSRF). Чтобы понять токен аутентичности, вы должны сначала понять атаки CSRF.
Предположим, что вы являетесь автором bank.com
. На вашем сайте есть форма, используемая для перевода денег на другую учетную запись с запросом GET:
Хакер может просто отправить HTTP-запрос серверу, сказав GET /transfer?amount=$1000000&account-to=999999
, правильно?
Неправильно. Атака хакеров не сработает. Сервер будет в основном думать?
А? Кто этот парень пытается начать передачу. Это не владелец учетной записи, это точно.
Как сервер знает об этом? Потому что нет session_id
cookie, аутентифицирующий запросчика.
Когда вы входите в систему со своим именем пользователя и паролем, сервер устанавливает 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
... будет установлен файл cookie session_id
, и сервер подумает, что пользователь должен перевести 1 000 000 долларов на счет 999999!
Хорошо, просто не посещайте опасные сайты, и все будет хорошо.
Этого недостаточно. Что делать, если кто-то размещает этот образ в Facebook и появляется на вашей стене? Что делать, если он вводится на сайт вашего посещения с помощью атаки XSS?
Это не так уж плохо. Только запросы GET уязвимы.
Не верно. Форма, которая отправляет запрос POST, может динамически генерироваться. Вот пример из Rails Guide on Security:
<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="✓" />
<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) - это как. Но это другая уязвимость для другого дня.
Методы Где authenticity_token
требуется
authenticity_token
требуется в случае идемпотентных методов, таких как post, put и delete, потому что методы Idempotent влияют на данные.
Зачем требуется
Требуется предотвратить злые действия. authenticity_token хранится в сеансе, всякий раз, когда на веб-страницах создается форма для создания или обновления ресурсов, то токен аутентификации хранится в скрытом поле и отправляется с формой на сервер. Перед выполнением действия пользователь отправил authenticity_token, перекрестно проверено с помощью
authenticity_token
, сохраненного в сеансе. Еслиauthenticity_token
совпадает, то процесс продолжается, иначе он не выполняет действия.
Что такое authentication_token?
Это случайная строка, используемая приложением rails, чтобы убедиться, что пользователь запрашивает или выполняет действие со страницы приложения, а не из другого приложения или сайта.
Почему требуется аутентификация_token?
Чтобы защитить ваше приложение или сайт от подделки запроса на межсайтовый сайт.
Как добавить аутентификацию_token в форму?
Если вы создаете форму с использованием тега form_for, то автоматически добавляется идентификатор_имя_науки, вы можете использовать <%= csrf_meta_tag %>
.