Rails 错误的 csrf token 会重置 session 啊!

aisensiy · 2013年03月27日 · 最后由 fsword 回复于 2013年03月28日 · 6960 次阅读

在 Guides 看到 http://guides.rubyonrails.org/security.html

If the security token doesn’t match what was expected, the session will be reset.

我觉得这也会导致一种攻击啊,session 被重置不就 logout 了么,每次被发个站外请求就被 logout 也不行啊

别人都改你 session 了,要是还能正常操作不是更危险。。。 更正:post, put, delete 等都是操作数据的语义,当然很危险

#2 楼 @jjym 举个场景:访问 A 站,获得了 session,接着访问 B 站,B 站有某个 js 代码不靠谱,创建一个 form 并提交到 A 站,这时好像确实没什么必要去 reset session,反而对用户形成干扰

楼主的质疑我也想不出有什么不合理,要不直接提个 pull request 给 rails?

#3 楼 @fsword B 站凭什么可以提交表单到 A 啊

可以记录 csrf 的 referrer 来提醒用户该网页有问题... airbrake 的异常统计里也能看到哪个站在使坏或者被注入了...

另外重置的是 session 不是 cookie, 如果有"记住我"的设置的话一般会写到 cookie 中而不是 session 中,所以登出的用户只包含没点选"记住我"的那些...

#4 楼 @zgm 那你的意思是?

#4 楼 @zgm 自己画个 form 就行啊

#3 楼 @fsword 可以指定某些 action 除外

#2 楼 @jjym 乱发跨站 post 不需要获取 session 对吧 这是两码事

#5 楼 @luikore 开玩笑啊 我的登录状态是在 session 里面的啊 默认的 current_user 是因为 session 里面有当前的 user_id

我发现这个问题就是因为我有个扩展向页面发请求,每次都会被 logout 啊,我一直找问题在哪里,最后发现是这个问题啊。

#4 楼 @zgm 这个问题你可以去我上面给的那个链接里找原因啊~

#3 楼 @fsword 对啊 其实就是拒绝这样的请求就好了,为什么要重置 session 呢

#8 楼 @bhuztez #11 楼 @aisensiy

csrf 这个处理方式是凝聚了无数经验的结果...

有跨站的需要就 protect_from_forgery except: [...] 呗。或者对 API 调用整个关掉 csrf 验证。

跑题:csrf 还有各种坑在里面,例如浏览器会缓存页面,如果打开一个登录页面,关闭浏览器再打开浏览器,session 失效,session 里的 csrf token 就和页面上的不一致了,但登录是能成功的。因为 csrf 失效只是清空了 session, 然后登录的话不用验证 session 里的 user id 的,所以还能正常登录,而且这样是没有危险的...

#14 楼 @luikore 可是我就是实实在在的被 logout 了啊

#14 楼 @luikore 还有我比较晕的就是 我是默认的 cookie_store 的 session 它怎么清空的?把我 cookies 干掉了么

#13 楼 @aisensiy 2#口误..如果直接拒绝掉可能会造成我就感觉好眼熟.. 另外 session 和 cookie 当然可以在服务器端操作..

#16 楼 @aisensiy 响应头有个 Set-Cookie 段修改的。

把你扩展页面发的请求附上正确的 csrf token, 修好不就没问题了么... 又没有谁在攻击你

@Guest (原 hooopo) 转推: “错误的 csrf token 会重置 session 是为了防穷举爆破啦..“ ,好吧,现在我同意 hooopo 了,有谁愿意进一步讨论么?

#19 楼 @fsword 穷举爆破什么啊....

#19 楼 @fsword 好吧,我自己进一步讨论:csrf 的攻击受到很多限制,比如尝试的时间有限(和会话生命周期相同),另外为了获取 cookie,攻击代码只能在浏览器上植入(求反驳),所以最多也就是 chrome 插件这种地方可以做穷举爆破。但是缺省情况下 rails csrf token 的值很大,穷举成本非常高,所以似乎也不能算是安全隐患 @Guest

#14 楼 @luikore 你说得详细点成不,我感觉乱了

HTTP Header

Cookie: session-id=xxxxxxxx

数据库里的 Session

{csrf-token: "zzzzzzzzzzzzzzzzzz", user-id: 12345}

重置 session 不就啥都没有了...

#24 楼 @bhuztez 嗯我说得太粗略了。其实和 session 的实现相关,rails 里 session 默认是整个 base64 或者加密了加上签名存 cookie 里的,然后 cookie 中的这个 session 项的生命期是没设的,所以关闭浏览器就没了。session 用数据库或者内存存储的话处理会不太一样. 但是实现 remember me 的话,往往是加上一个 expire 比较长的 cookie (那么 cookie 就变成 session=...;remember_me=...;expires=... 了), 关闭浏览器也还存在,清空 session 的动作是不消除其它 cookie 的,这种情况基本没影响... 但如果像 ruby-china 这样,把 session 项也设置上生命期来记住用户登录状态,重置 session 确实什么都没了。

#22 楼 @fsword 好像 Referer 不对直接干掉就好了...

#25 楼 @luikore 有两个地方有补充:

rails 里 session 默认是整个 base64 或者加密了加上签名存 cookie 里的

这个地方是先将 session Marshal dump 然后再 Base64

但是实现 remember me 的话,往往是加上一个 expire 比较长的 cookie (那么 cookie 就变成 session=...;remember_me=...;expires=... 了), 关闭浏览器也还存在,清空 session 的动作是不消除其它 cookie 的,这种情况基本没影响...

这里如果 session 被删除了,即使 cookie 还在也会登出了,因为在应用层的 filter 如果找不到 session 中用于标识用户的信息,会验证失败吧。除非把这些东西都放在 cookie 中,每次取也从 cookie 中取,那 session 没了也没什么影响。

#27 楼 @zgm 这个地方处理可以很神奇的... 可以是单单对 csrf 请求重置了 session, 然后下个正常请求又按照 cookie 登录,设上 user_id, 就又是登录状态了...

#26 楼 @bhuztez 不是这么简单的,用 curl 都可以伪造 Referrer

#29 楼 @luikore 你都 CURL 就不是 CSRF 了...

#22 楼 @fsword 是啊 穷举一个页面上的 token??这个太没意义了吧,logout 一次就变了啊

#31 楼 @aisensiy 我也觉得这个穷举 没什么意义,但是 Rails 4 这块处理变了,你可以去看看:23 楼。

#30 楼 @bhuztez 浏览器可以不发 referrer 的,另外代理也可能会改掉 referrer

#33 楼 @luikore 你说的都超出 CSRF 的层面了啊...

#30 楼 @bhuztez curl 和 跨站的效果一样吧 都是没有合法的 token

#34 楼 @bhuztez 有关系啊,你喀擦掉了 referrer 不对的请求,然后那些浏览器设置了不加 referrer 的和一些用了 http proxy 的用户都提交不了正常的表单了,用 csrf token 验证的话就不会误杀这类用户

#36 楼 @luikore 强制 CSRF+Referrer 验证...没有更好的办法了

#32 楼 @zgm

3.2

def handle_unverified_request
  reset_session
end

4.0

def handle_unverified_request
  request = @controller.request
  request.session = NullSessionHash.new(request.env)
  request.env['action_dispatch.request.flash_hash'] = nil
  request.env['rack.session.options'] = { skip: true }
  request.env['action_dispatch.cookies'] = NullCookieJar.build(request)
end

我贴出来 大家鉴赏吧

@bhuztez 不用也不应验证 referrer... 强制 referrer 也就防盗链有点用而且体验极烂...

@aisensiy 这个修改是允许加 with: :null_session 的选项吧?就是单对非法请求清空了 session, 下个请求里 session 就又恢复了。

#39 楼 @luikore 前面是说 csrf-token 被穷举爆破咋办...

#39 楼 @luikore 靠 我看不懂啊 我这几个类 NullSessionHash NullCookieJar 以及 那几个 env hash 都不知道是干什么的!

#41 楼 @aisensiy 重设了一遍 cookie,这个处理似乎还是不太好

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