ActionController :: InvalidAuthenticityToken

148

Ниже приведена ошибка, вызванная формой в моем приложении Rails:

Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

Это происходит для каждого не- getзапроса и, как вы видите, authenticity_tokenесть.

Никита Рыбак
источник

Ответы:

207

У меня была такая же проблема, но со страницами, которые были кэшированы. Страницы буферизировались с использованием устаревшего токена подлинности и всех действий с использованием методов post / put / delete, которые распознавались как попытки подделки. Ошибка (422 Unprocessable Entity) была возвращена пользователю.

Решение для Rails 3:
Добавить:

 skip_before_filter :verify_authenticity_token  

или, как указано в «Сагиво» в Rails 4, добавить:

 skip_before_action :verify_authenticity_token

На страницах, которые делают кеширование.

Как @toobulkeh прокомментировал это не уязвимость в :index, :showдействиях, но остерегайтесь использовать это на :put, :postдействий.

Например:

 caches_page :index, :show  
 skip_before_filter :verify_authenticity_token, :only => [:index, :show]

Ссылка: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

Примечание, добавленное barlop-Rails 4.2, устарело skip_before_filter в пользу skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html "Семейство методов * _filter было удалено из документации. Их использование не рекомендуется в пользу * _action семейство методов "

Для Rails 6 (как указывалось в «collimarco») вы можете использовать skip_forgery_protectionи то, что это безопасно использовать для REST API, который не использует данные сеанса.

Szymon Jeż
источник
3
Это вряд ли так, я не знал о caches_page до вашего поста. Но я проверю caches_page , спасибо.
Никита Рыбак
7
в рельсах 4skip_before_action :verify_authenticity_token
Сагив Офек
88
Разве это не уязвимость?
Quantumpotato
6
это не уязвимость в :index, :showдействиях. Но будьте осторожны с этим :put, :post!
Toobulkeh
14
хотя я согласен, что у вас есть случаи, когда это необходимо (например, возможно, один раз в жизни), но вы должны понимать, что вы исправляете безопасность, отключая ее. Не рекомендуется
эквивалент 8
77

Для меня причиной этой проблемы под Rails 4 было отсутствие,

<%= csrf_meta_tags %>

Линия в моем основном макете приложения. Я случайно удалил его, когда переписал свой макет.

Если этого нет в основном макете, он понадобится вам на любой странице, на которой вы хотите использовать токен CSRF.

Джеймс МакМэхон
источник
2
Мы также получаем эту ошибку. Но это прерывается. Может ли это быть причиной или не иметь это влияет на каждый запрос с ошибкой?
Райан-Нил Мес
@ Ryan-NealMes, если в вашем шаблоне отсутствует эта строка, вы получите ошибку. Так что, возможно, некоторые из ваших шаблонов имеют его, а другие нет.
Джеймс МакМэхон
1
@JamesMcMahon спасибо, я понял, что мой случай на самом деле вызван тем, что пользователи очищают свои куки или блокируют их. Узнал много от этого вопроса!
Райан-Нил Мес
61

Есть несколько причин этой ошибки (относящихся к Rails 4).

1. Проверьте наличие <%= csrf_meta_tags %>в макете страницы.

2. Убедитесь, что токен подлинности отправляется с вызовами AJAX, если используется form_forпомощник с remote: trueопцией. Если вы не можете включить строку <%= hidden_field_tag :authenticity_token, form_authenticity_token %>с блоком формы.

3. Если запрос отправляется с кэшированной страницы, используйте кэширование фрагментов, чтобы исключить часть страницы, которая отправляет запрос, например, button_toи т. Д. В противном случае токен будет устаревшим / недействительным.

Я не хотел бы аннулировать защиту CSRF ...

GoodViber
источник
csrf_meta_tags должен быть в <head>? Как я могу быть уверен, что он не конфликтует с турболинками?
блеск
37

Просто добавив authenticity_tokenв форму исправил это для меня.

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Дипак Махакале
источник
3
Rails должен отправлять токен по умолчанию. Мы не хотим указывать это явно. Я чувствую, что токен как-то изменился в этой ситуации здесь.
Абхи
1
Однако, если вы создали свою форму без помощи помощников, вы должны поместить ее вручную.
Андре Гимарайнш Саката,
30

Маркер подлинности - это случайное значение, сгенерированное, по вашему мнению, для подтверждения того, что запрос отправлен из формы на вашем сайте, а не где-то еще. Это защищает от CSRF-атак:

http://en.wikipedia.org/wiki/Cross-site_request_forgery

Проверьте, кто этот клиент / IP, похоже, они используют ваш сайт без загрузки ваших просмотров.

Если вам нужно продолжить отладку, этот вопрос является хорошим началом: Понимание токена подлинности Rails

Отредактировано для объяснения: это означает, что они вызывают действие для обработки отправки вашей формы, даже не отображая вашу форму на вашем веб-сайте. Это может быть вредоносным (например, публикация спам-комментариев) или указание на то, что клиент пытается напрямую использовать API вашего веб-сервиса. Вы единственный, кто может ответить на этот вопрос в зависимости от характера вашего продукта и анализа ваших запросов.

Уинфилд
источник
1
Спасибо, но я уже знаю, что такое маркер подлинности. Проверьте, кто этот клиент / IP, похоже, они используют ваш сайт без загрузки ваших просмотров. Извините, что значит "без загрузки просмотров"?
Никита Рыбак
1
Я имею в виду, что кто-то (возможно, спамер) может отправлять данные в вашу форму, не обращаясь к пользовательскому интерфейсу вашего приложения. Это можно сделать с помощью программы командной строки, например, curl.
Джон Топли
Джон совершенно верно. Это означает, что они вызывают действие для обработки отправки вашей формы, даже не отображая вашу форму на вашем веб-сайте. Это может быть вредоносным (например, публикация спам-комментариев) или указание на то, что клиент пытается напрямую использовать API вашего веб-сервиса. Вы единственный, кто может ответить на этот вопрос в зависимости от характера вашего продукта и анализа ваших запросов.
Уинфилд
Хорошо, я неправильно понял комментарий Уинфилда. Я думал, что приложение не было настроено так, чтобы «загружать мои представления», когда я использую браузер.
Никита Рыбак
1
У меня также была другая мысль, эти запросы включают токен, но он не действителен. Это может быть вызвано кэшированием страницы, отображающей вашу форму, или чем-то еще, что потенциально может привести к устаревшей версии формы.
Уинфилд
27

ActionController::InvalidAuthenticityTokenтакже может быть вызвано неверно настроенным обратным прокси. Это тот случай, если в трассировке стека вы получите строку, похожую на следующую Request origin does not match request base_url.

При использовании обратного прокси-сервера (такого как nginx) в качестве приемника для запроса HTTPS и передачи запроса в незашифрованном виде на бэкэнд (например, приложение Rails), бэкэнд (более конкретно: Rack) ожидает некоторые заголовки с дополнительной информацией об исходном клиентском запросе для того, чтобы иметь возможность применять различные задачи обработки и меры безопасности.

Более подробная информация доступна здесь: https://github.com/rails/rails/issues/22965 .

TL; DR: решение состоит в том, чтобы добавить несколько заголовков:

upstream myapp {
  server              unix:///path/to/puma.sock;
}

location / {
  proxy_pass        http://myapp;
  proxy_set_header  Host $host;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_set_header  X-Forwarded-Ssl on; # Optional
  proxy_set_header  X-Forwarded-Port $server_port;
  proxy_set_header  X-Forwarded-Host $host;
}
vmarquet
источник
Ух ты, я три часа искал решение для этого, и на этом все, спасибо!
Evexoio
Большое спасибо за 6 часов попыток решить эту проблему на стороне рельсов
Джо Половина
18

слишком поздно, чтобы ответить, но я нашел решение.

Когда вы определяете свою собственную 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, а не удалять, понижать или обновлять rails.

Amjad
источник
9

Если вы сделали rake rails:updateили недавно изменили свою версию config/initializers/session_store.rb, это может быть признаком старых файлов cookie в браузере. Надеемся, что это сделано в dev / test (это было для меня), и вы можете просто удалить все куки браузера, связанные с данным доменом.

Если это в работе, и вы изменили key, подумайте о том, чтобы вернуть его обратно, чтобы использовать старые куки (<- только предположение).

Kross
источник
Да! Для меня наличие пустого session_store.rb было причиной ошибки.
Lafeber
6

У меня была эта проблема с вызовами JavaScript. Я исправил это, просто потребовав jquery_ujs в файл application.js.

Майкл Копер
источник
Да, верно, у меня тоже была эта проблема, и я добавил jquery_ujs в приложение js. Это сработало.
Абхи
3

У нас была та же проблема, но мы заметили, что это было только для запросов, использующих http: //, а не с https: //. Причина была secure: trueдля session_store:

Rails.application.config.session_store(
  :cookie_store,
  key: '_foo_session',
  domain: '.example.com',
  secure: true
)

Исправлено с помощью HTTPS ~ везде :)

Darep
источник
Я столкнулся с этим при использовании rails s(не-SSL) вместо конечной точки SSL, которую я настроил для разработки. Только когда я прочитал ваш комментарий, я понял, что я делаю. Как только я вернулся к использованию SSL, все снова заработало. Спасибо!
Карл Уилбур
1
Я столкнулся с этой проблемой в разработке. Вместо того, чтобы secure: trueя написалsecure: !Rails.env.development?
Мурб
1

Для рельсов 5 лучше добавить, protect_from_forgery prepend: trueчем пропуститьverify_authentication_token

aadeshere1
источник
5
Зачем? Не могли бы вы добавить ссылку?
Кверле
1

Добавить

//= require rails-ujs 

в

\app\assets\javascripts\application.js
Майкон Дуглас
источник
0

У меня была эта проблема, и причина была в том, что я скопировал и вставил контроллер в свое приложение. Мне нужно было перейти ApplicationControllerнаApplicationController::Base

user2954587
источник
0

У меня была такая же проблема на localhost. Я изменил домен для приложения, но в файле URLs и hosts был еще старый домен. Обновил закладки моего браузера и файл hosts для использования нового домена, и теперь все работает нормально.

MoD
источник
0

Может быть, у вас есть настройки NGINX для HTTPS, но ваши сертификаты недействительны? У меня была похожая проблема в прошлом, и перенаправление с http на https решило проблему

montrealmike
источник
0

Я проверил наличие <% = csrf_meta_tags%> и очистка куки в браузере сработала для меня.

Правин К.Дж.
источник
0

Следуя рекомендациям Chrome Lighthouse для ускорения загрузки приложений, я установил асинхронный Javascript:

views/layout/application.html.erb

<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>

Это сломало все и получило ошибку токена для моих удаленных форм. Удаление async: trueисправило проблему.

Maxence
источник
0

Этот ответ гораздо более конкретен для Ruby on Rails, но, надеюсь, он кому-нибудь поможет.

Вам необходимо включать токен CSRF в каждый не GET-запрос. Если вы привыкли использовать JQuery, Rails имеет вспомогательную библиотеку, которая называется jquery-ujsповерх нее и добавляет некоторые скрытые функции. Одна из вещей, которые он делает, автоматически включает токен CSRF в каждый ajaxзапрос. Смотрите здесь .

Если вы откажетесь от этого, как я, вы можете оказаться с ошибкой. Вы можете просто отправить токен вручную или использовать другую библиотеку, чтобы помочь очистить токен от DOM. Смотрите этот пост для более подробной информации.

user2490003
источник
0

В среде разработки я попытался решить многие из этих проблем в Rails 6. Ни одна из них не помогла. Поэтому, если ни одно из этих предложений не сработало, попробуйте ниже.

Единственное решение, которое я нашел, было добавить txt файл в вашу папку / tmp.

В корневом каталоге вашего приложения запустите:

touch tmp/caching-dev.txt

Или вручную создайте файл с таким именем в папке / tmp. Поскольку это исправило это для меня, я предполагаю, что корень проблемы - конфликт кеширования.

Twistedben
источник
-1

В рельсах 5 нам нужно добавить 2 строки кода

    skip_before_action :verify_authenticity_token
    protect_from_forgery prepend: true, with: :exception
giapnh
источник
-2

Установка

gem 'remotipart' 

может помочь

Alexei.B
источник
3
хотя это может быть ответом, но также полезно включить основную часть ответа и объяснить, почему / как это работает.
Рой Ли
-15

Проблема решена снижением до 2.3.5 с 2.3.8. (а также печально известный вопрос «Вы перенаправлены».)

Никита Рыбак
источник
@ Flip, возможно, это идея обновить принятый ответ?
Lafeber