×

对csrf 和jwt的一些思考

Falcon 2021-01-16 views:
自动摘要

正在生成中……

看了两天 restful api 和csrf,我觉得slim3csrf中间件设计得太过度了,带来了不必要的麻烦。

1. 是生成机制,生成的csrf token值要用随机字符串可以理解,为什么生成的key也要用随机字符串,而这个随机字符串的key所起的作用只是存储token value的一个键,而为了检验这个key,客户端不但要提供csrf token值的字段,还要额外提供一个key的隐藏字段,完全没必要搞得那么复杂 ;

2. 是csrf token验证过一次后,立刻销毁并且重新生成,也就是说token是一次性有效,貌似是更安全了,可这也带来了其他的问题,在普通的网页请求中没有问题,问题在于使用ajax请求时,同一个页面可以发起多个请求,就意味着第一个请求后,csrf token被销毁,后面再用这个token就无效了,解决方法是一个请求成功后,在响应的数据中返回一组新的token,在后续的请求append这个token。或者新增一个专门获取csrf token接口,我看到有篇文章提到这个方案,他是把Djangocsrf token 机制改成一次性的,但我可以想到这样做的一些安全隐患,如果接口被跨域,比如支持CORS,或者用flash主动请求这个接口就可以在站外获得一组 token ,再配合构造一个提交页面,就可以通过csrf 验证。不过我又想到如果用其他方式,只要支持cors和用flash请求,依然可以通过其他接口获得token,好像只能说明不恰当地配置cors危害很大,至于 flash 我不太了解,存疑。

我依然认为没有必要做一次性的csrf token,同时可以简化csrf 的结构,目前的结构是哈希数组 比如:[{hash_key1:hash_token1},{hash_key2:hash_token2}],这意味着客户端必须提交两个输入值,我觉得只要放在一个普通的有序数组就可以了比如 [ hash_token1, hash_token2 ] ,而还有一点,这个中间件只能从请求体获取token,不会从请求头取得,在做ajax请求时又是不舒服的,于是我继承这个Guard类自己实现了一个新的子类,并暴露出一些给twig用的助手函数。

 

还有一些关于jwt的思考,我在考虑做api的用户认证时看到的。如果用传统的session或者cookie的方式,必须提供一组csrf token,没有问题,WordPress Rest API 默认就使用这种方式 ,而对jwt ,有些误解认为这个天然防CSRF,这分两种情况,取决于jwt的验证机制,客户接收到jwt之后,可以存储在cookie或者local storage,如果将token存储在cookie里的,那么请求接口时会自动带上cookie,如果服务端只对cookie验证jwt,这样依然会被csrf ,这种情况还是要附上csrf token追加保护;如果存储在local storage,请求的时候附在请求头,如

Authorization: Bearer <token>

这样确实可以防 csrf ,因为local storage不能跨域读取,所以可以认为这个操作是安全的。

阮一峰这篇 JWT 入门的文章写得很不错, 文章讲到传统的session机制存在的一个缺点,很难支持两个站点同时登录,jwt 似乎是可以解决这个问题,但具体的流程文章没有详述,我模拟一下这个过程,用户在A站点登录后,获得一个jwt,这时用这个token向B站点请求,把token放在请求头,如果是浏览器环境,B站点首先应该支持cors, 但如果支持cors,用传统的session/cookie也能做到同步登录,不过服务器需要配置session的跨站点校验,比如用redis管理共同的seesion,不过能做到不代表容易做,用jwt确实更简单一些,不过我认为jwt的意义可能更多在手机app、支持跨域的小程序,浏览器扩展等,这仍然是一个值得使用的技术。