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.