前后端分离csrf,xss,session, jwt,token的实现

以下观点纯属个人理解。如有问题,还请指出。

建议阅读:

  • http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
  • https://juejin.im/post/5bc009996fb9a05d0a055192

csrf: 别的网站里有一个链接是你的网站的url,如果你登录了你的网站,导致别人网站引用你的链接会有危险。
xss:你的网站有类似输入的功能,这个功能有可能有安全漏洞,会执行恶意用户的js代码,获取到用户的cookie。

1 使用jwt

这种方式可以很快速的开发,提供一个接口返回jwt,前端保存,每一次提交带上。后端不需要做数据存储,只需要做解析token里面的用户id既可。
前后端分离的应用,可以使用jwt这种方式,jwt内容里面存能够标识用户的数据(用户ID),由于jwt只是防止伪造,是可以查看里面的内容的。如果要实现用户状态管理,可以重新生成jwt,对旧的加入黑名单。由于jwt特点,它的有效性检验和它设置的过期时间有关,没过期,那么它就是有效的,所以要额外有一个黑名单。

前端jwt token存放位置,如果存放在本地存储中,这样要预防xss。不过自然也不用处理csrf,因为你每次请求都要从local storage带上这个token设置到请求头里面,其它网站无法得到这个token,当然手机app由于权限问题,你app的数据不能被其它软件访问,也就没有xss问题,这样以来,个人觉得,jwt挺适合手机app开发的。

如果把jwt token存放到cookie(http only)上,会有csrf的问题,但是解决了xss,js无法获取httponly的cookie。

网上的一段话:(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

也就是说一个用户在手机A中登录了,然后又在手机B中登录,在过期之前手机A和B都可以登录,无法做到B登录后让A过期,如果要做到这点,就必须让服务器维护一个清单(记录该账号是否已经签发token),这样又回到session的老路了。

jwt要结合一些后端存储技术来处理业务。

2 使用session

session机制在前端使用比较简单,手机app上也可以实现,比jwt麻烦一点。
后端请求接口,会在浏览器设置一个sessionid, 假设这个是一个uuid,用户请求的是login接口,把这个sessionid作为键存储到redis中,值为用户唯一id,再把这个sessionid发给前端,一般会直接设置在前端cookie上,并且设置cookie属性为httponly。
这样会有csrf问题,又再需要引入csrftoken值。每一次post提交,在head和cookie带上csrf token。后端对比这两个值。
这时候xss是无法得到sessionid。

如果把sessionid 作为一个token,存储到前端的localstorage, 这时候xss可以得到localstorage,但是预防了csrf。

还有一种比较新的cookie属性,可以在攻击者csrf攻击的时候,不同的网站发出的请求不会携带该cookie。same-site。相信未来会使用这种方式解决csrf。因为这个本身是浏览器做的事情。

3 使用Token

使用jwt又一定机率暴露用户的关键身份表示。使用令牌可能是大多数web后端选择的实现,令牌和session类似。令牌通常是一个在数据库中(redis)的一个key,这个key在python中可以使用uuid生成随机,既然这个是随机的,那么就很难伪造。这个key对应的value通常是一个用户的唯一表示,比如数据库User表中的id主键。在前端每次ajax请求都需要在Header中携带Token字段,服务端收到请求去判断这个Token(key),是否合法,然后再去数据库(redis)中查找对应的uid,例如,用户请求的是获取用户地址的接口,那么自然就得到了用户的id,就可以做关联查询去查询数据库的地址数据。通常我们在接口中是禁止携带uid这种的,为了安全。也因为不同于JWT,Token它可以查到存储到服务器的值。

要点

  • 将jwt存放在local_storage 前提是确保你的js脚本不会读取这个jwt

  • 将jwt存放在cookie httponly里面,你需要和session一样预防csrf。后端需要csrf值设置到前端的浏览器上。

  • 用户退出,需要拉黑token,token在创建的时候就决定了它死亡时间,除非你用黑名单这种方式将它拉黑

  • jwt,Token对移动端友好

  • 在重要的cookie加上安全属性,在非https不会带上cookie

  • 使用sessionid存放到前端cookie http only里面。你需要预防csrf

  • 后端根据前端传进来sessionid获取指定用户

在未来,相信csrf的问题浏览器自己就会解决。

总结

csrf和xss 如何预防取决于你数据存放在哪,相比而言,csrf更容易防护,把数据放在cookie httponly里面来主要预防xss。
使用jwt的话,前端需要把token放在httponly的cookie才安全。同时还要预防CSRF。
预防csrf其中一个实现,是在HTTP请求头设置一个csrf token,在http only的jwt token的数据字段里面加上一个csrf token。后端对比这两个csrf token进行判断(参考flask-jwt-extended实现)。
使用Token实现登录认证应该是目前前后端分离的主流。

参考

  • http://www.redotheweb.com/2015/11/09/api-security.html

  • https://flask-jwt-extended.readthedocs.io/en/latest/tokens_in_cookies.html

你可能感兴趣的:(前后端分离csrf,xss,session, jwt,token的实现)