модуль ActionController::RequestForgeryProtection
Действия контроллера защищены от атак Cross-Site Request Forgery (CSRF) путём добавления токена в рендеренный HTML вашего приложения. Этот токен хранится как случайная строка в сессии, к которой злоумышленник не имеет доступа. Когда запрос достигает вашего приложения, Rails проверяет полученный токен с токеном в сессии. Проверка выполняется только для запросов HTML и JavaScript, поэтому это не защитит ваш XML API (вероятно, у вас будет другая схема аутентификации).
GET-запросы не защищаются, так как они не имеют побочных эффектов, таких как запись в базу данных, и не раскрывают конфиденциальную информацию. JavaScript-запросы являются исключением: сторонний сайт может использовать тег <script> для ссылки на JavaScript-URL на вашем сайте. Когда ваш JavaScript-ответ загружается на их сайте, он выполняется. При тщательно составленном JavaScript на их стороне конфиденциальные данные в вашем JavaScript-ответе могут быть извлечены. Чтобы предотвратить это, только запросы XmlHttpRequest (известные как XHR или Ajax) разрешены для выполнения GET-запросов для JavaScript-ответов.
Важно помнить, что запросы XML или JSON также затронуты, и если вы создаёте API, вам понадобится что-то вроде:
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
end
Защита CSRF включена с помощью метода protect_from_forgery, который проверяет токен и сбрасывает сессию, если он не соответствует ожидаемому. Вызов этого метода по умолчанию генерируется для новых приложений Rails.
Параметр токена по умолчанию имеет имя authenticity_token. Имя и значение этого токена должны быть добавлены в каждый макет, который рендерит формы, включив csrf_meta_tags в HTML head.
Узнайте больше об атаках CSRF и защите вашего приложения в Руководстве по безопасности Ruby on Rails.
Константы
- CROSS_ORIGIN_JAVASCRIPT_WARNING
Защищённые методы экземпляров
Параметр подлинности формы. Переопределите, чтобы предоставить свой собственный.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 254 def form_authenticity_param params[request_forgery_protection_token] end
Устанавливает значение токена для текущей сессии.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 249 def form_authenticity_token session[:_csrf_token] ||= SecureRandom.base64(32) end
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 201 def handle_unverified_request forgery_protection_strategy.new(self).handle_unverified_request end
GET-запросы проверяются на межсайтовый JavaScript после рендеринга.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 222 def mark_for_same_origin_verification! @marked_for_same_origin_verification = request.get? end
Если `verify_authenticity_token` before_action был запущен, проверяется, что JavaScript-ответы передаются только GET-запросам с одинаковым источником.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 228 def marked_for_same_origin_verification? @marked_for_same_origin_verification ||= false end
Проверка межсайтовых JavaScript-ответов.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 233 def non_xhr_javascript_response? content_type =~ %r(\Atext/javascript) && !request.xhr? end
Проверяет, разрешает ли контроллер защиту от подделки.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 259 def protect_against_forgery? allow_forgery_protection end
Возвращает true или false, если запрос проверен. Проверки:
-
Это GET или HEAD запрос? GET запросы должны быть безопасными и идемпотентными
-
Совпадает ли #form_authenticity_token с заданным значением токена из параметров?
-
Совпадает ли заголовок X-CSRF-Token с #form_authenticity_token
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 242
def verified_request?
!protect_against_forgery? || request.get? || request.head? ||
form_authenticity_token == params[request_forgery_protection_token] ||
form_authenticity_token == request.headers['X-CSRF-Token']
end Фактическое before_action, используемое для проверки токена CSRF. Не переопределяйте его напрямую. Вместо этого предоставьте собственную стратегию защиты от подделки. Если вы переопределите, вы отключите проверку межсайтового `<script>`.
Опирайтесь на объявление protect_from_forgery, чтобы отметить, какие действия требуют проверки запросов с одинаковым источником. Если protect_from_forgery включён для действия, это before_action помечает его после_action для проверки того, что JavaScript-ответы предназначены для XHR-запросов, гарантируя, что они следуют политике одинакового источника браузера.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 192
def verify_authenticity_token
mark_for_same_origin_verification!
if !verified_request?
logger.warn "Can't verify CSRF token authenticity" if logger
handle_unverified_request
end
end Если `verify_authenticity_token` был выполнен (что указывает на то, что защита от подделки включена для этого запроса), то также проверьте, что мы не предоставляем несанкционированный ответ с другим источником.
# File actionpack/lib/action_controller/metal/request_forgery_protection.rb, line 214
def verify_same_origin_request
if marked_for_same_origin_verification? && non_xhr_javascript_response?
logger.warn CROSS_ORIGIN_JAVASCRIPT_WARNING if logger
raise ActionController::InvalidCrossOriginRequest, CROSS_ORIGIN_JAVASCRIPT_WARNING
end
end
© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.