Rails 7中Invisible Captcha时间戳阈值与Devise confirmable不触发问题
部署在fly.io上的Rails 7应用新增了约10个机器人账号,已安装配置Invisible Captcha gem,设置400秒时间戳阈值后验证未触发。当前环境情况:
- Devise启用
confirmable选项,用户需点击确认链接才能访问站点 - 使用TomSelect JS实现注册时角色选择
- 注册表单能看到
<%= invisible_captcha %>生成的隐藏字段,HTML结构如下:
<div class="akycjhmgilspxv_1669858439"><style media="screen">.akycjhmgilspxv_1669858439 {position:absolute!important;height:1px;width:1px;overflow:hidden;}</style><label for="akycjhmgilspxv">How often do you go out dancing?</label><input type="text" name="akycjhmgilspxv" id="akycjhmgilspxv" autocomplete="off" tabindex="-1"><input type="hidden" name="spinner" id="spinner" value="0427cfe9c26b1956983b7f12163dbb94" autocomplete="off"></div>
相关配置代码:
- routes.rb:
devise_for :users, :path => '', :path_names => { :sign_in => "login", :sign_out => "logout", :sign_up => "register" }, controllers: { registrations: 'users/registrations' } devise_scope :user do match '/register.user', to: 'devise/registrations#create', via: :post end
- config/initializers/invisible_captcha.rb:
InvisibleCaptcha.setup do |config| # config.honeypots << ['more', 'fake', 'attribute', 'names'] # config.visual_honeypots = false config.timestamp_threshold = 400 # config.timestamp_enabled = true # config.injectable_styles = false # config.spinner_enabled = true # Leave these unset if you want to use I18n (see below) config.sentence_for_humans = 'How often do you go out dancing?' config.timestamp_error_message = 'Something went wrong, please try again.' end
- 注册控制器:
class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] invisible_captcha only: [:create] end
已重启服务器,但400秒阈值仍未生效,疑惑是否只能依赖机器人填写隐藏字段来拦截。
1. 启用时间戳验证核心开关
你的初始化配置里config.timestamp_enabled = true被注释掉了,这是时间戳验证生效的必要条件。取消注释该配置:
InvisibleCaptcha.setup do |config| # ...其他保留配置 config.timestamp_threshold = 400 config.timestamp_enabled = true # 取消注释这行 # ...其他保留配置 end
修改后重新部署应用,确保配置生效。
2. 修正路由指向自定义控制器
你额外添加的match '/register.user', to: 'devise/registrations#create', via: :post路由,指向了Devise默认的注册控制器,而非你添加了invisible_captcha回调的自定义控制器users/registrations。
要么删除这条冗余路由,要么修改为指向自定义控制器:
devise_scope :user do match '/register.user', to: 'users/registrations#create', via: :post end
确保所有注册请求都经过带验证码验证的控制器动作。
3. 排除TomSelect的干扰
TomSelect本身不会影响验证码,但如果你的JS代码在表单提交前有修改字段、篡改提交时间的操作,可能导致时间戳验证失效。可以暂时禁用TomSelect测试注册流程,验证时间戳是否生效。
4. 检查请求参数完整性
查看机器人提交的请求日志,确认是否携带了spinner字段(时间戳参数)。如果机器人请求未携带该参数,时间戳验证应该触发拦截;若参数被篡改,也会触发验证失败。
5. 补充honeypot字段增强拦截
如果时间戳验证仍有遗漏,可以添加多个假字段(honeypot),增加机器人误填概率:
InvisibleCaptcha.setup do |config| config.honeypots << ['favorite_color', 'pet_name'] # 添加额外隐藏假字段 # ...其他保留配置 end
这些字段对正常用户不可见,机器人若填写则会被直接拦截。
内容的提问来源于stack exchange,提问作者Ogarocious

