开源项目 RuCaptcha 的验证码可以被攻击重放?

firebroo · 发布于 2016年10月14日 · 最后由 HackBraid 回复于 2016年10月17日 · 1656 次阅读
17365

初学rails, 写了个blog,然后上社区搜到了这个 @huacnlee 写的gem做为验证码,因为我是做安全的,所有习惯性测试了验证码是否可以被复用,首先chrome开f12,然后评论一条,copy出数据包如下

curl 'http://www.firebroo.com/categorys/20/articles/11/comments' -H 'Cookie: _blog_session=eTBGSkNhYTlUWmYrSDlEN2k2TEV5NEwvRjhmTUdIQTQ3WUdFQ08vaXFhbnhEdGp6RTJHNjVqVmVFL3haVEtnZ2xBaE51ZUR3cTFIcGY3SWIzd2p0WXIxdG1QQWhBemNIUkJYV3B5SGIySmhERmhqNWpoc2lqdEJTSDJTclBaRG51VXpGaWgwenFDcWIrY2JqWWUrZHpKcG1NcExWbVNxNzBYRUV2M01VL0Jibk15TjVqZXBYRktsbWlnM2M5eDNCbWZrOE5XQzhqaUxDUmttWHNETHovSWg5MmZ4V25reDErUVVuaC9MTkVxZ3YrQlk0aFJUcFZwM0dmcFRkajZFUkRDeVllNVhyN1BtQkxQNXYydCtuQURMQ3Bhc0plMXMwYUNRRVp2eUMwWUZxRW9vcFRDUTNhalMxVFAyZVQ3YjdXM3FQTXoxbU1HWGVBajNEc0NDd2VZdHJlUU96Q0N4QlY0YS9VN0RLL0JodEpJMjF1SnpibjBUMURFK2FXL1V6UTI3bkM3ZFFrOVFnR0ZkY0E4cUpiL2s1SHB2WmpvRHRzUWpFK1gxeUh0eXJ4WStQMUZUYVRpdXlWZ2diMjVOZkZyNUxzdGJjOFJrUmdUZnhlM3grV3BsTjN3M3h5SGNlVzRmMEp6bHl3M0E9LS1WQlpNbzgvNjNNb201OGRYTVdPTHhBPT0%3D--d72e796e819742de283b32395b295ee6503be124' -H 'Origin: http://www.firebroo.com' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http://www.firebroo.com/categorys/20/articles/11.html' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=SLFcb%2FjeKgBJ2IyZ%2FgG5Itbcbv%2F9dftg8os6r1MZF9Msgk7imr7IcOev8b5Kdz0bOugb8NiQBhhVfH5vX%2F1MuA%3D%3D&comment%5Bcommenter%5D=firebroo&comment%5Bbody%5D=111&_rucaptcha=2d72&commit=%E6%8F%90%E4%BA%A4' --compressed

只要我多次不断执行这条命令,评论就会不断添加。达到绕过验证码实现重放攻击。 然后去github看了verify_rucaptcha?函数,发现验证码设计流程应该是没问题的,无论验证码正确与否,都会被session.delete注销。

def verify_rucaptcha?(resource = nil)
  rucaptcha_at = session[:_rucaptcha_at].to_i
  captcha = (params[:_rucaptcha] || '').downcase.strip

  # Captcha chars in Session expire in 2 minutes
  valid = false
  if (Time.now.to_i - rucaptcha_at) <= RuCaptcha.config.expires_in
    valid = captcha.present? && captcha == session.delete(:_rucaptcha)
  end

  if resource && resource.respond_to?(:errors)
    resource.errors.add(:base, t('rucaptcha.invalid')) unless valid
  end
end

我打印过出重放请求时候的session的_rucaptcha, 发现和首次评论的验证码值一样,所以session.delete没有删除成功还是有啥缓存?

共收到 22 条回复
96

这应该是没有delete掉

96

你这个是session重放攻击了吧,
rucaptcha是验证码信息存在session里的,验证码默认有效期是两份钟.
你用一个正确的session在有效期内重发,server 每次都会从session里解析出验证码和有效期 两个都是正确的,验证就通过了...

1107

是的 Rails的session是通过cookie实现的,不是Rucaptalcha的问题

11524

session, session_id 放在 cookie 里面, 你每次都带相同的 cookie 怎么删得掉啊。

17365

#3楼 @jasl #4楼 @gyorou session通过cookies实现的啊。。那这种重放刷的问题靠验证码已经解决不了了。。 #2楼 @759803573 我以为rails的sessions也会存服务器。

1107

#5楼 @firebroo Session通过Cookie来储存Rails的默认方案,这块叫做 SessionStore,如果你需要后端来储存Session,也是很容易修改的

17365

#6楼 @jasl 刚查到了,rails设置默认的session存储方式很不安全啊。。

De6df3

这不是 Rails Session 的问题,是 rucaptcha 的问题,设计的时候忘了这个茬。

1107

#7楼 @firebroo Rails的方式安全,表单的重放攻击可以通过 CSRF Token 来防止,即你在控制器加入 protect_from_forgery (在ApplicationController默认包含的,所以其子类都会受到保护),这时候,你在生成的HTML的 <head></head> 里可找到形如 <meta name="csrf-token" content="8MCrc1N+u+FfLYTsrpqsLW41/I0s3rWf6zk6Cib2tt5T0pu1ErBMAeWIkd5AlFJ3Q69b/k8vX14dxZ7RBFVDfA=="> 的标签,在遵守Rails的标准开发方式的时候,当表单提交时,其中的 content 会作为请求头的 X-CSRF-Token 字段传递给后端(由jquery_ujs 实现),这块通过一个 Rack 中间件来处理(没记错的话) 但是在采用非Rails标准方式实现的时候,或者暴露API的应用,这个机制会失效

17365

#9楼 @jasl 好吧,我看了一点点rails guide就开始写着玩了。。 #8楼 @huacnlee 恩,后来各种搜,看到了指南有说明默认方式会存在攻击重放问题,我现在把session放数据库解决了问题。

1107

#11楼 @firebroo 应该还是不用的,你主贴的curl里请求也并没包含 CSRF 相关的头,这时候(遵守Rails的默认写法前提下),这个请求应该会抛出异常 建议你还是先检查下 CSRF相关的保护有没做好(在控制器这边),按标准实践来实现功能

De6df3

Gem 问题已修复,改用 Cache 存储验证码到服务端。

https://github.com/huacnlee/rucaptcha/commit/e129851fd982bdf5e8cc2c6bbf0d3b11a27bc248

  • rucaptcha 1.0.1
17365

#12楼 @jasl 我的表单有authenticity_token字段,app/controllers/application_controller.rb里面也有protect_from_forgery with: :exception,应该没问题吧。CSRF攻击和这种重放攻击有区别,token验证的设计方式一般是在cookies里面放置一个加密的,然后表单放置一个明文的,提交的时候解密cookies里面的token然后和表单提交的来对比,我用上面的包重放,两个永远相等。所以csrf token无法防御这种重放的,token的真实应用场景是别人无法拿到你cookies里面的token(当然可以配合xss拿到cookie另说),如果我加密了token存在cookies里面,基本拿到cookies也没法知道明文的token。然后就起到了防御CSRF攻击的作用。

De6df3

#9楼 @jasl CSRF Token 只能避免跨站攻击,没法避免重放攻击,拷贝相同的 Cookie、表单、相同的环境执行是有效果的

17365

#13楼 @huacnlee 动作好快啊。

De6df3

#15楼 @firebroo 再帮忙验证一下

17365

#17楼 @huacnlee 恩,我刚测试了,1.0.1已经确认修复了。

1107

#14楼 @firebroo 恩 我错了

96

#13楼 @huacnlee 今天为了这个cookies琢磨了一下午,没想到你这么快就更新了。👍

17365

#19楼 @jasl 没事,很感谢你给我的回复~.~

96

@firebroo 不错不错,学习了~

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册