Rails 4 Токен Подлинности


198

Я работал над новым приложением Rails 4 (на Ruby 2.0.0-p0), когда столкнулся с некоторыми проблемами с токенами подлинности.

При написании контроллера, который отвечает на json (используя respond_toметод класса), я получил createдействие, которое я начал получать ActionController::InvalidAuthenticityTokenисключения, когда пытался создать запись с использованием curl.

Я удостоверился, что установил, -H "Content-Type: application/json"и я установил данные с, -d "<my data here>"но все еще не удача.

Я попытался написать тот же контроллер с использованием Rails 3.2 (на Ruby 1.9.3), и у меня не возникло проблем с токеном подлинности. Я искал вокруг и увидел, что в Rails 4 произошли некоторые изменения с токенами аутентичности. Насколько я понимаю, они больше не вставляются автоматически в формы? Я предполагаю, что это как-то влияет на не-HTML типы контента.

Есть ли способ обойти это без необходимости запрашивать HTML-форму, перехватывая токен аутентификации, а затем отправляя другой запрос с этим токеном? Или я полностью упускаю что-то совершенно очевидное?

Изменить: Я только что попытался создать новую запись в новом приложении Rails 4, используя скаффолд, не меняя ничего, и я столкнулся с той же проблемой, поэтому я думаю, что это не то, что я сделал.

Ответы:


277

Я думаю, я только что понял это. Я изменил (новый) по умолчанию

protect_from_forgery with: :exception

в

protect_from_forgery with: :null_session

согласно комментарию в ApplicationController.

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

Вы можете увидеть разницу, посмотрев на источник request_forgery_protecton.rbили, более конкретно, на следующие строки:

В Rails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

В Rails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Который назовет следующее :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end

20
Вы можете удалить опцию: with вместе, по умолчанию: null_session
— Кейси

6
Есть ли способ использовать исключение для вызовов не-JSON и нулевой сеанс для вызовов JSON (иначе называемых вызовами API)?
— Джеймс МакМэхон

@JamesMcMahon Вы можете написать свой собственный, before_actionкоторый проверяет формат и проверяется ли запрос. Я не знаю ни одного встроенного способа установить условия.
— alexcoco

1
В rails 4.1.6 мне также пришлось указать skip_before_action :verify_authenticity_tokenна контроллере приложения моего API, чтобы эта работа работала.
— Васим

1
Вам больше не нужно отключать :verify_authenticy_tokenв Rails 4.2. По умолчанию используется значение :null_session, которое, как следует из названия, просто дает вам запрос без сеанса. Вместо этого вы можете проверить запрос через ключ API.
— Лобати

72

Вместо того, чтобы выключать защиту csrf, лучше добавить следующую строку кода в форму

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

и если вы используете form_for или form_tag для генерации формы, то она автоматически добавит вышеуказанную строку кода в форму


9
Это хороший совет, если вы создаете форму, но вопрос касается выполнения вызовов API с использованием JSON.
— Джеймс МакМэхон

1
Спасибо, однако, это ответило на мой вопрос о написании кода вручную при использовании руля!
— Дэвид Роутен

70

Добавление следующей строки в форму работало для меня:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

12
на самом деле не относится к вызовам API
— courtimas

2
В моем случае я использую Rails4. Я могу отправить форму, нажав кнопку отправки. Но если я отправляю форму через код JS, эта ошибка возникает. И этот ответ решил проблему для меня.
— Chris.Zou

2
Для моего приложения на Rails 4.0.8 этого было достаточно, чтобы написать =token_tag nilили (в .erb)<%= token_tag nil %>
— jmarceli

1
Вы, кажется, отключаете аутентификацию, устанавливая токен на ноль?
— Карлос

безопасно ли это делать?
— Анхель Гарсия

33

Я не думаю, что хорошо вообще отключать защиту CSRF, если вы не используете исключительно API.

Просматривая документацию по Rails 4 API для ActionController, я обнаружил, что вы можете отключить защиту от подделки для каждого контроллера или для каждого метода.

Например, чтобы отключить защиту CSRF для методов, которые вы можете использовать

class FooController < ApplicationController
  protect_from_forgery except: :index

Это сделало это для меня в Rails 4 - ошибка выдается после попытки удаления. ^^
— zero_cool

9

Наткнулся на ту же проблему. Исправлено, добавив в мой контроллер:

      skip_before_filter :verify_authenticity_token, if: :json_request?

неопределенный метод `json_request? ' для # <SettingsController: 0x000000030a54a8>, есть идеи?
— Деано

Вы должны определить метод там как: def json_request? request.format.json? конец
— Джай Кумар Раджпут

7

Ты пробовал?

 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }

4

В этом официальном документе рассказывается о том, как правильно отключить защиту от мошенничества для API http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html.


1
Это правда, но ответ с 2013 года - и все меняется. И хотя ваш официально принятый ответ хорош - моя ссылка просто дает более глубокий обзор предмета
— konung


2

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

Вот так,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Вот несколько строк для разных версий рельсов.

Рельсы 3

skip_before_filter: verify_authenticity_token

Рельсы 4 :

skip_before_action: verify_authenticity_token


Если вы намереваетесь отключить эту функцию безопасности для всех подпрограмм контроллера, вы можете изменить значение protect_from_forgery на : null_session в вашем файле application_controller.rb.

Вот так,

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end

1

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

JQuery-UJS может управлять токенами для вас

Он должен быть уже в составе гема jquery-rails, но вам может понадобиться включить его в application.js с

//= require jquery_ujs

Это все, что вам нужно - теперь ваш Ajax-вызов должен работать

Для получения дополнительной информации см .: https://github.com/rails/jquery-ujs.



0

Когда вы определяете свою собственную HTML-форму, вы должны включить строку токена аутентификации, которую следует отправить контроллеру из соображений безопасности. Если вы используете rails form helper для генерации токена подлинности, он добавляется в форму следующим образом.

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
  </div>
    ...
</form>

Таким образом, решение проблемы состоит в том, чтобы либо добавить поле authenticity_token, либо использовать помощники формы rails, чем поставить под угрозу безопасность и т. Д.


1
Спасибо за ваш ответ, хотя это не отвечает на оригинальный вопрос. Был задан вопрос об ответе на запросы JSON, но вы предоставляете решение для HTML-формы с нуля. При выполнении запросов JSON (например, API) вы не отправляете форму HTML, и у вас может не быть легкого доступа к токену подлинности.
— alexcoco

если только содержимое запроса не является JSON, в этом случае вы захотите установить его application/json.
— alexcoco

Я понимаю, что ответ не совсем то, что вы ищете. Но цель поставить связанный ответ состоит в том, чтобы помочь пользователям, ищущим подобные "Проблемы подлинности".
— Amjad

извините, я ошибочно удалил - "вы можете установить Content-Type: application / x-www-form-urlencoded с указанным выше решением".
— Amjad

0

Все мои тесты работали нормально. Но по какой-то причине я установил переменную окружения как non-test:

export RAILS_ENV=something_non_test

Я забыл сбросить эту переменную, из-за которой я начал получать ActionController::InvalidAuthenticityTokenисключения.

После сброса $RAILS_ENVмои тесты снова начали работать.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.