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

177

Я работал над новым 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 приложении, используя эшафот, ничего не меняя, и я столкнулся с той же проблемой, поэтому я думаю, что это не то, что я сделал.

Теги:
ruby-on-rails-4
authenticity-token

13 ответов

282
Лучший ответ

Думаю, я просто понял это. Я изменил (новый) по умолчанию

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 : api.rubyonrails.org/classes/ActionController/…
  • 6
    Есть ли способ использовать исключение для вызовов не-JSON и нулевой сеанс для вызовов JSON (иначе вызовы API)?
Показать ещё 5 комментариев
65

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

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  • 12
    на самом деле не относится к вызовам API
  • 2
    Еще более лаконично, чем приведенный выше код. Спасибо!
Показать ещё 4 комментария
64

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

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

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

  • 9
    Это хороший совет, если вы создаете форму, но вопрос касается выполнения вызовов API с использованием JSON.
  • 1
    Спасибо, однако, это ответило на мой вопрос о написании кода вручную при использовании руля!
31

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

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

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

class FooController < ApplicationController
  protect_from_forgery except: :index
  • 0
    Это было сделано для меня в Rails 4 - ошибка при попытке удаления. ^^
8

Произошла одна и та же проблема. Исправлено, добавив к контроллеру:

      skip_before_filter :verify_authenticity_token, if: :json_request?
  • 0
    неопределенный метод `json_request? ' для # <SettingsController: 0x000000030a54a8>, есть идеи?
  • 0
    Вы должны определить метод там как: def json_request? request.format.json? конец
6

Вы пытались?

 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 года - и все меняется. И хотя ваш официально принятый ответ хорош - моя ссылка просто дает более глубокий обзор предмета
3

Это функция безопасности в Rails. Добавьте эту строку кода в форму:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

Документацию можно найти здесь: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

2

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

Таким образом,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

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

Рельсы 3

skip_before_filter: verify_authenticity_token

Rails 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

Добавить authenticity_token: true в тег формы

0

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

export RAILS_ENV=something_non_test

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

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

0

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

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

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

//= require jquery_ujs

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

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

0

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню