Рейки 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, або, більш конкретно, наступних рядків:

У рейках 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

У рейках 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Який зателефонує наступним чином :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end

20
Ви можете видалити: з опцією всі разом,: null_session є типовим: api.rubyonrails.org/classes/ActionController/…
Casey

6
Чи є спосіб використовувати виняток для дзвінків, що не належать до JSON, та нульового сеансу для дзвінків JSON (він же API виклики)?
Джеймс Макмахон

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

1
У рейках 4.1.6 мені довелося також вказати skip_before_action :verify_authenticity_tokenна контролері мого додатка API, щоб зробити цю роботу.
Waseem

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або (in .erb)<%= token_tag nil %>
jmarceli

1
Ви, здається, відключили автентифікацію, встановивши маркер нуля?
Карлос

чи безпечно це робити?
Ангел Гарсія

33

Я не думаю, що загалом вимкнути захист CSRF до тих пір, поки ви не реалізуєте виключно API.

Переглядаючи документацію API Rails 4 для 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_поперед запуску: verify_authenticity_token


Якщо ви маєте намір вимкнути цю функцію безпеки для всіх процедур контролера, ви можете змінити значення protection_from_forgery на : null_session у вашому файлі application_controller.rb.

Так,

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

1

Якщо ви використовуєте jQuery з рейками, будьте обережні, щоб дозволити вхід до методів, не перевіряючи маркер автентичності.

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

Ви повинні мати його вже як частину дорогоцінного каміння jquery-rails, але, можливо, вам потрібно буде включити його в 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>

Тож рішення проблеми - або додати поле автентичності_токена, або використовувати рейки для помічників, а не шкодити безпеці тощо.


1
Дякую за вашу відповідь, хоча це не відповідає на початкове запитання. Питання про відповідь на запити JSON, але ви надаєте рішення для HTML-форми з нуля. Коли ви робите запити JSON (думаю API), ви не надсилаєте HTML-форму, і у вас може не бути легкого доступу до маркера автентичності.
alexcoco

якщо тільки вміст запиту не є насправді JSON, у цьому випадку ви хочете його встановити application/json.
alexcoco

Я розумію, що відповідь - це не саме те, що ви шукаєте. Але мета відповіді відповіді - допомогти користувачам, які шукають подібні "Проблеми автентичності".
amjad

Вибачте, що я видалив помилково - "Ви можете встановити Content-Type: application / x-www-form-urlencoded з вищевказаним рішенням".
amjad

0

Всі мої тести працювали чудово. Але чомусь я встановив мінливу середовища для не тесту:

export RAILS_ENV=something_non_test

Я забув зняти цю змінну, через що почав отримувати ActionController::InvalidAuthenticityTokenвиключення.

Після скидання $RAILS_ENVмої тести знову почали працювати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.