You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7部署至Heroku时无法验证CSRF token authenticity报错

Rails应用Heroku部署后CSRF校验失败、登录401问题

问题表现

应用本地localhost运行正常,部署到已配置SSL证书、未使用Cloudflare的Heroku环境后,登录操作异常,日志输出如下:

Error R14 (Memory quota exceeded)
Started POST "/users/sign_in?locale=en" for 115.31.132.11 at 2022-07-04 15:19:04 +0000
Processing by Users::SessionsController#create as HTML
     Parameters: {"authenticity_token"=>"gLidqKg8CS6bv....", "user"=>{"email"=>"test@gmail.com", "password"=>"[FILTERED]", "remember_me"=>"1"}, "commit"=>"Log in", "locale"=>"en"}
    Can't verify CSRF token authenticity.
Started GET "/profiles?locale=en" for XXX.XXX.XXX.XXX at 2022-07-04 16:40:43 +0000
Processing by ProfilesController#index as HTML
Parameters: {"locale"=>"en"}
Completed 401 Unauthorized in 84ms (Allocations: 1320)
Started GET "/users/sign_in?locale=en" for X.X.X.X at 2022-07-04 16:40:43 +0000
Processing by Users::SessionsController#new as HTML

日志显示POST请求已携带CSRF参数,Heroku环境变量SECRET_TOKEN配置正确。

现有配置

  • app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
  protect_from_forgery
end
  • config/environments/production.rb相关配置:
config.force_ssl = false 

config.cache_store = :redis_cache_store, {
    namespace: 'cache',
    expires_in: 24.hours,
    driver: :hiredis, 
    url: ENV.fetch("REDIS_CACHE_URL") { "redis://localhost:6379/1" },
  }

config.session_store :cookie_store, expire_after: 1.year, domain: :all

排查确认问题和domain: :all配置直接相关,但业务必须保留该配置,以支持fr.dashboard.example.com、es.dashboard.example.com等多子域会话共享。


问题根因

Rails中domain: :all的逻辑是自动提取当前访问域名的根域,设置为session cookie的作用域。如果直接使用Heroku默认分配的xxx.herokuapp.com域名访问,Rails会把cookie域设置为公共后缀herokuapp.com,所有主流浏览器都会出于安全策略拦截这类公共后缀下的cookie写入,导致session无法在请求间正常传递,服务端拿不到session中存储的CSRF token,即使请求参数里带了token也会校验失败,最终返回401未授权。
日志里的Error R14 (Memory quota exceeded)是dyno内存超出配额的告警,和本次登录失败问题无直接关联,若修复后仍有该告警可单独优化内存占用或升级dyno规格。

修复方案

在保留多子域会话共享能力的前提下,按以下步骤调整即可解决:

  1. 为Heroku应用绑定自有根域名(比如example.com),将所有业务子域(fr.dashboard.example.com、es.dashboard.example.com等)都解析到该Heroku应用,不要直接使用默认的herokuapp.com域名对外提供服务。
  2. 修改生产环境session_store配置,显式指定顶级域长度,不要直接裸用domain: :all:
config.session_store :cookie_store, 
  expire_after: 1.year, 
  domain: :all,
  tld_length: 2, # 对应example.com这类双段根域,若使用example.com.cn这类更长后缀则调整为3
  secure: Rails.env.production?, # HTTPS环境下仅传输cookie,提升安全性
  httponly: true # 禁止前端JS读取cookie,降低XSS风险
  1. 由于环境已经配置了SSL证书,建议把config.force_ssl改为true,强制所有请求走HTTPS,避免cookie被明文窃听。
  2. 部署更新后,清空浏览器本地存储的旧域名cookie,再重新测试登录流程即可。

内容的提问来源于stack exchange,提问作者sparkle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 08:24:21