Rails не может проверить подлинность токена CSRF только на Heroku/производстве

Приложение нормально работает локально как в режиме разработки, так и в рабочем режиме, но после развертывания на Heroku проверка CSRF завершается сбоем. Это ванильный запрос без ajax.

Локально я работаю в производственном режиме с

RAILS_ENV=production heroku local -e production

Я хотел убедиться, что это реальная проблема, поэтому я отключил проверку токена подлинности, и версия Heroku тоже заработала.

Обновление: вот моя конфигурация:

# session_store.rb:
Hlresponse::Application.config.session_store :cookie_store, key: '_hlresponse_session', domain: :all

# Environment:

$ heroku config:set MIN_THREADS=1 MAX_THREADS=1

# Procfile:

web: bundle exec puma -C config/puma.rb

# config.ru:

require ::File.expand_path('../config/environment',  __FILE__)
run Rails.application

# puma.rb:

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

Вот два набора журналов, один без ошибки (и проверка отключена), а другой с включенной проверкой, с ошибкой. Любая идея о том, как подойти к этому?

С отключенным verify_authenticity_token (skip_before_action :verify_authenticity_token)

Jun 05 23:46:58 hlevents app/web.1:  Started POST "/admin/snippets" for 64.69.46.217 at 2015-06-06 06:46:57 +0000 
Jun 05 23:46:58 hlevents heroku/router:  at=info method=POST path="/admin/snippets" host=hlevents.herokuapp.com request_id=5de24f22-13bb-43ff-a8f1-d65efd08b879 fwd="64.69.46.217" dyno=web.1 connect=0ms service=15ms status=302 bytes=1047 
Jun 05 23:46:58 hlevents app/web.1:  Processing by SnippetsController#create as HTML 
Jun 05 23:46:58 hlevents app/web.1:  Processing by SnippetsController#index as HTML 
Jun 05 23:46:58 hlevents app/web.1:    Rendered shared/admin/_include_bootstrap.html.erb (0.1ms) 
Jun 05 23:46:58 hlevents app/web.1:    Rendered shared/admin/_breadcrumbs.html.erb (0.2ms) 
Jun 05 23:46:58 hlevents app/web.1:    Parameters: {"utf8"=>"✓", "authenticity_token"=>"oPdNjND12fwYrx8YdxhdQLqs67JbX8MkNxyGGj8NS2DwxHxe5HK2Fl+FdOSEs4t73ISoGPgF24YeZphwOmsNGg==", "snippet"=>{"name"=>"test2", "draft_content"=>"test2"}, "save_as_draft"=>"true", "commit"=>"Create Snippet"} 
Jun 05 23:46:58 hlevents app/web.1:  Redirected to https://hlevents.herokuapp.com/admin/snippets 
Jun 05 23:46:58 hlevents app/web.1:  Completed 302 Found in 10ms (ActiveRecord: 4.0ms) 
Jun 05 23:46:58 hlevents app/web.1:  Started GET "/admin/snippets" for 64.69.46.217 at 2015-06-06 06:46:58 +0000 
Jun 05 23:46:58 hlevents app/web.1:    Rendered snippets/index.html.erb within layouts/application (3.9ms) 
Jun 05 23:46:58 hlevents app/web.1:    Rendered shared/admin/_menu.html.erb (0.4ms) 
Jun 05 23:46:58 hlevents app/web.1:  Completed 200 OK in 8ms (Views: 5.4ms | ActiveRecord: 1.2ms) 

С включенным verify_authenticity_token:

Jun 05 23:49:38 hlevents app/web.1:  Started POST "/admin/snippets" for 64.69.46.217 at 2015-06-06 06:49:38 +0000 
Jun 05 23:49:38 hlevents app/web.1:  Processing by SnippetsController#create as HTML 
Jun 05 23:49:38 hlevents app/web.1:  Can't verify CSRF token authenticity 
Jun 05 23:49:38 hlevents app/web.1:  ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/request_forgery_protection.rb:181:in `handle_unverified_request' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/request_forgery_protection.rb:209:in `handle_unverified_request' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/request_forgery_protection.rb:204:in `verify_authenticity_token' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:432:in `block in make_lambda' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:164:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:164:in `block in halting' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:504:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:504:in `block in call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:504:in `each' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:504:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:92:in `_run_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:776:in `_run_process_action_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:81:in `run_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/callbacks.rb:19:in `process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/rescue.rb:29:in `process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications.rb:164:in `block in instrument' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/notifications.rb:164:in `instrument' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/instrumentation.rb:30:in `process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/params_wrapper.rb:250:in `process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/railties/controller_runtime.rb:18:in `process_action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/abstract_controller/base.rb:137:in `process' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionview-4.2.1/lib/action_view/rendering.rb:30:in `process' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal.rb:196:in `dispatch' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal/rack_delegation.rb:13:in `dispatch' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_controller/metal.rb:237:in `block in action' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:74:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:74:in `dispatch' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:43:in `serve' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:43:in `block in serve' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:30:in `each' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/journey/router.rb:30:in `serve' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/routing/route_set.rb:819:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/etag.rb:24:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/conditionalget.rb:38:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/head.rb:13:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/params_parser.rb:27:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/flash.rb:260:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/session/abstract/id.rb:225:in `context' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/session/abstract/id.rb:220:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/cookies.rb:560:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/query_cache.rb:36:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:649:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:88:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:88:in `_run_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:776:in `_run_call_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/callbacks.rb:81:in `run_callbacks' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/callbacks.rb:27:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/remote_ip.rb:78:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/show_exceptions.rb:30:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:38:in `call_app' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:20:in `block in call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:68:in `block in tagged' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:26:in `tagged' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/tagged_logging.rb:68:in `tagged' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/rack/logger.rb:20:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/request_id.rb:21:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/methodoverride.rb:22:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/runtime.rb:18:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    Parameters: {"utf8"=>"✓", "authenticity_token"=>"g0mFZ2tEDMvvSiq3FeIUPFTWiwi8N4LO4cs81PkohjoesgtJgGnQ6I7x+L4kwgMFoqHQHYfqQeznMQduOBzgmQ==", "snippet"=>{"name"=>"test3", "draft_content"=>"test3"}, "save_as_draft"=>"true", "commit"=>"Create Snippet"} 
Jun 05 23:49:38 hlevents app/web.1:  Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms) 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.1/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/middleware/static.rb:113:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/rack-1.6.0/lib/rack/sendfile.rb:113:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/engine.rb:518:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/railties-4.2.1/lib/rails/application.rb:164:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/configuration.rb:51:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/server.rb:507:in `handle_request' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/server.rb:375:in `process_client' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/server.rb:262:in `block in run' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/thread_pool.rb:104:in `call' 
Jun 05 23:49:38 hlevents app/web.1:    vendor/bundle/ruby/2.2.0/gems/puma-2.11.3/lib/puma/thread_pool.rb:104:in `block in spawn_thread' 
Jun 05 23:49:38 hlevents heroku/router:  at=info method=GET path="/favicon.ico" host=hlevents.herokuapp.com request_id=c0616b75-9fb0-4ee0-990d-52f2a34333f2 fwd="64.69.46.217" dyno=web.1 connect=0ms service=5ms status=200 

person aaandre    schedule 06.06.2015    source источник
comment
Вы переопределили разработку HTML?   -  person Dipak Gupta    schedule 06.06.2015
comment
Я не использую devise. Аутентификации пока нет.   -  person aaandre    schedule 06.06.2015
comment
Можете ли вы обновить snippets форму, о которой идет речь?   -  person Dipak Gupta    schedule 06.06.2015
comment
Нет. Ничто из того, что требует проверки csrf, не работает в производстве.   -  person aaandre    schedule 06.06.2015
comment
Возможно, вы не используете тег формы rails, поэтому в вашей форме не создается поле подлинности. Вот почему я попросил вас обновить представление формы. Убедитесь, что вы используете тег формы rails form_tag или html.   -  person Dipak Gupta    schedule 06.06.2015
comment
Да, я использую form_for. Как проверить, используется ли правильный тег подлинности?   -  person aaandre    schedule 06.06.2015
comment
Если ваш html генерируется нормально, то должен быть какой-то html, похожий на этот: <div style="margin:0;padding:0;display:inline"><input type="hidden" value="✓" name="utf8"><input type="hidden" value="xxxxxxxxxxxxxxxxxxxxxxxxx" name="authenticity_token"></div> Присутствует в вашей форме. Это автоматически генерируется в теге формы.   -  person Dipak Gupta    schedule 06.06.2015
comment
не могли бы вы опубликовать свой файл config/initializers/session_store.rb   -  person Amit Sharma    schedule 06.06.2015
comment
@AmitSharma добавил мою конфигурацию   -  person aaandre    schedule 06.06.2015
comment
где ваша конфигурация sessing_store   -  person Amit Sharma    schedule 06.06.2015
comment
@AmitSharma, я добавил этот параметр к вопросу (в файлах cookie).   -  person aaandre    schedule 07.06.2015
comment
@Dipak, я попробовал еще раз и убедился, что обновление действительно работает. Кроме того, я заметил, что файл cookie _hlresponse не отображается на Heroku. Итак, это проблема, связанная с файлами cookie! Локально я получаю ту же ошибку, если удаляю файл cookie перед публикацией редактирования.   -  person aaandre    schedule 07.06.2015
comment
Хорошо, похоже, проблема в domain: :all в выражении config.session_store. Я удалил это, и теперь файлы cookie работают и на Heroku. Однако для этого приложения мне потребуются многодоменные файлы cookie, но я рассмотрю это снова после настройки собственного домена и поддоменов для приложения.   -  person aaandre    schedule 07.06.2015
comment
удалите domain: :all и попробуйте запустить код.   -  person Amit Sharma    schedule 07.06.2015
comment
Спасибо, Амит, я уже сделал, как указал в комментарии выше твоего.   -  person aaandre    schedule 07.06.2015


Ответы (1)


Проблема была с domain: :all в конфигурации :cookie_store.

Hlresponse::Application.config.session_store :cookie_store, key: '_hlresponse_session', domain: :all

Я удалил его, и файлы cookie снова появились.

Hlresponse::Application.config.session_store :cookie_store, key: '_hlresponse_session'

Однако мне нужно будет включить этот параметр, так как я буду использовать несколько поддоменов. Я подожду, пока не настрою собственный домен на Heroku, и посмотрю, заработает ли он снова. Мне интересно, предпринимает ли Heroku попытку отключить файлы cookie с несколькими субдоменами в своем домене herokuapp.com...

person aaandre    schedule 06.06.2015
comment
Отключение файлов cookie с несколькими субдоменами на herokuapp.com имеет смысл! И, честно говоря, вы этого не хотите. Это будет означать, что любое приложение (а это будут десятки тысяч, если не больше) может читать ваши файлы cookie. Получите свой собственный домен (простой .com стоит 12 долларов в год с Google), настройте его для работы с Heroku без дополнительных затрат (даже бесплатные динамометры позволяют создавать собственные домены) - person Dirk de Kok; 07.06.2015
comment
Спасибо, это план. Я добавлю домен и желаемые поддомены, и если domain: :all будет работать с этой настройкой, я приму свой собственный ответ :) - person aaandre; 08.06.2015