Rails 3 CSRF 令牌仍在提交
Rails 3 CSRF token still submits
我在遗留 rails 应用程序中工作,我正在尝试清理一些 CSRF 漏洞。如果我从表单中删除隐藏的 CSRF 字段,我仍然可以成功提交表单。
唯一表明出现问题的迹象是日志中的警告:WARNING: Can't verify CSRF token authenticity
。
有一些页面 protect_from_forgery
会捕获请求,如果没有 csrf 令牌但应用程序会崩溃,具体取决于页面:例如。登录页面在没有令牌的情况下工作,但更新用户页面没有。
我已经尝试为 protect_from_forgery
制定自定义策略(Marc Gauthier 建议),例如:
protect_from_forgery with: :MyStrategy
class MyStrategy
byebug
def initialize(controller)
@contriller = controller
end
def handle_unverified_request
puts "HELLO!"
Rails.logger.warn [
"handle_unverified_request",
"#{@controller.controller_name}-#{@controller.action_name}"
].join(" - ")
end
end
这似乎在启动应用程序时没有执行任何操作,byebug
调用将暂停,但我从未收到 puts
消息或错误日志。
我也尝试过常规策略,例如 with: :exception
,但没有任何变化,有些页面有效,有些无效,但它们是一致的。
通常保护 logged-in 用户 session 免受 CSRF 攻击很重要,因此在许多应用程序中,通常会禁用对 login/logout 的保护以防止合法用户出错。在大多数情况下,如果 session 无论如何都会成为 terminated/reset,那么 RF 不会造成太大伤害。
寻找 skip_before_action :verify_authenticity_token
禁用正在由 protect_from_forgery
安装的操作
检查您的测试方法 - 隐藏的表单字段并不总是必要的,因为 rails 也使用 X-CSRF-Token
headers 用于 ajax 表单。要正确测试伪造保护 - 进行实际的伪造尝试,例如使用 curl
.
检查 config.action_controller.allow_forgery_protection
是否未被 development/production 禁用,并且控制器或其祖先没有 allow_forgery_protection
过载并为相关请求返回 false
。不太可能,但应用程序可能有一些其他部分的伪造保护被覆盖,请参阅 request_forgery_protection.rb
PS。 byebug
in class 上下文对于这种情况不是很有用,更明显的方法是 raise "Hello CSRF"
in handle_unverified_request
似乎 Rails 正在做它应该做的事情,只是重置会话,这在登录表单或忘记密码表单上并不重要。因为我们只有 protect_from_forgery
(with: :exception
直到 sometime in Rails 5 才成为默认值)。
有人会认为添加 with: :exception
会起作用,但事实并非如此。解决方法是提取异常 class 的内容并将它们放入 application_controller
:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
这适用于登录和忘记密码表单,其他表单(正确地不允许错误请求通过)保持不变,这有点奇怪,因为我认为两者都会因 InvalidAuthenticityToken raised
.
当然,这就留下了一个问题,为什么 protect_from_forgery with: :exception
不起作用?
我在遗留 rails 应用程序中工作,我正在尝试清理一些 CSRF 漏洞。如果我从表单中删除隐藏的 CSRF 字段,我仍然可以成功提交表单。
唯一表明出现问题的迹象是日志中的警告:WARNING: Can't verify CSRF token authenticity
。
有一些页面 protect_from_forgery
会捕获请求,如果没有 csrf 令牌但应用程序会崩溃,具体取决于页面:例如。登录页面在没有令牌的情况下工作,但更新用户页面没有。
我已经尝试为 protect_from_forgery
制定自定义策略(Marc Gauthier 建议),例如:
protect_from_forgery with: :MyStrategy
class MyStrategy
byebug
def initialize(controller)
@contriller = controller
end
def handle_unverified_request
puts "HELLO!"
Rails.logger.warn [
"handle_unverified_request",
"#{@controller.controller_name}-#{@controller.action_name}"
].join(" - ")
end
end
这似乎在启动应用程序时没有执行任何操作,byebug
调用将暂停,但我从未收到 puts
消息或错误日志。
我也尝试过常规策略,例如 with: :exception
,但没有任何变化,有些页面有效,有些无效,但它们是一致的。
通常保护 logged-in 用户 session 免受 CSRF 攻击很重要,因此在许多应用程序中,通常会禁用对 login/logout 的保护以防止合法用户出错。在大多数情况下,如果 session 无论如何都会成为 terminated/reset,那么 RF 不会造成太大伤害。
寻找 skip_before_action :verify_authenticity_token
禁用正在由 protect_from_forgery
检查您的测试方法 - 隐藏的表单字段并不总是必要的,因为 rails 也使用 X-CSRF-Token
headers 用于 ajax 表单。要正确测试伪造保护 - 进行实际的伪造尝试,例如使用 curl
.
检查 config.action_controller.allow_forgery_protection
是否未被 development/production 禁用,并且控制器或其祖先没有 allow_forgery_protection
过载并为相关请求返回 false
。不太可能,但应用程序可能有一些其他部分的伪造保护被覆盖,请参阅 request_forgery_protection.rb
PS。 byebug
in class 上下文对于这种情况不是很有用,更明显的方法是 raise "Hello CSRF"
in handle_unverified_request
似乎 Rails 正在做它应该做的事情,只是重置会话,这在登录表单或忘记密码表单上并不重要。因为我们只有 protect_from_forgery
(with: :exception
直到 sometime in Rails 5 才成为默认值)。
有人会认为添加 with: :exception
会起作用,但事实并非如此。解决方法是提取异常 class 的内容并将它们放入 application_controller
:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
这适用于登录和忘记密码表单,其他表单(正确地不允许错误请求通过)保持不变,这有点奇怪,因为我认为两者都会因 InvalidAuthenticityToken raised
.
当然,这就留下了一个问题,为什么 protect_from_forgery with: :exception
不起作用?