
这是一场关于身份的战斗,这是一次关于资源的权衡
首先列举一下关于身份验证的相关组件和他们代表的本质
cookie,即存储到用户端设备中的数据,可控性堪忧,存在多种常见的容易攻击的方式。
session,即存储到单服务节点中的数据,可控性高,但是得和cookie结合使用,分布式系统几乎不可用。
redis,mysql,即存储到独立的服务节点中的数据,可控性高,分布式系统使用方便,但是代价就是额外的io和存储开销。
jwt,即存储到字符串中,可控性为零,但是自带状态,分布式系统使用方便,不需要额外io开销,性能好。
总结完上述组件发现各有特色,各自的缺点也很明显
cookie安全性低,不可控,容易受到xss攻击,重放攻击等等,但是为了进行鉴权,用户端逻辑上是必须要有存储的地方,所以cookie只能作为一个容器来使用,安全性低到默认是无安全即是最好的态度,这里只要能保证一点即可完成本教程的设计,即jwt不能在用户没有操作的情况下被第三方直接读取就可,这是最低保障,剩下的用户自行泄漏等并不在系统设计考虑之内。
session必须依赖cookie才能运行,相当于将数据信息加密的安全责任放到服务器,所以会多出一小部分计算消耗,这种模式在单体服务场景下已经是最优解,但是在分布式系统,多服务交换信息的场景下设计难度非常地狱,局限性很大。
redis和mysql这种独立服务看似很完美,但是作为非同一个系统内交换数据带来的延迟,计算压力和会比直接在内存中读取不知道多几个数量级,会导致在多次鉴权的场景下带来爆炸的服务器压力。
jwt是个看似很完美的解决方案,但是他是无状态的,服务端对jwt的掌控权从签署到用户拿到的那一刻就脱离了控制,就场景来说,用户在改变密码重新登录后,只要旧的jwt没有过期,就可以达到和新的密码一样的效果,这是恐怖的后果,你只要泄漏了jwt令牌,即便你察觉到并修改密码也无法阻挡别人使用你用户的信息,这是致命的缺点。由于存储jwt的往往是安全性堪忧的用户端。这种缺点就会无限放大。
脱离了需求谈工具,也是耍流氓,在不同的需求下如何使用这些组件?
首先,极致的需求必定伴随着极致的代价,编程绝没有所谓的银弹。
需求:极致的安全性还要分布式
极致的安全就代表着jwt这种无状态不可控的方式是不可以使用的,分布式代表着session的使用是捉襟见肘的,所以只能用redis和mysql加上cookie来实现鉴权,但是代价就是用户的每一次请求都会访问数据库,极致的安全,极致的计算开销,极致的延迟,这就是代价。
需求:极致的安全的单体服务
cookie加session用就对了
需求:管他什么安全,极致的节省计算资源和空间资源和计算资源
直接用对称加密将身份信息保存到cookie中,不使用session,到后端直接秘钥解密就能鉴权,不同服务器用一个秘钥,还能实现分布式鉴权
需求:安全几乎没有,分布式的,相对节省资源的
单使用jwt就可以,鉴权不用读取数据库,分布式方便,自带签名和加密,相对安全
需求:不保证绝对的安全,分布式的,资源消耗适中的
这是本章的重点,在上述需求中,大部分人都想又方便,又想比较安全,又想不会资源消耗过度,这种权衡是取其精华的过程。
这个方式核心思想是将需求分离,
保证安全又要分布式就必须要有状态就必须要读取数据库,但不是所有的操作都是非常敏感的,你给别人点个赞不必费大劲保证你的安全。这部分敏感操作是低频的,要独立分出去。
用户其他低敏感度的行为是高频的,是需要降低资源消耗的,所以jwt的自带状态和信息是必须的,来减少对数据库的访问量,但是jwt的可控性太低,所以有效期不能太长,但是有效期短用户就得频繁登录,很麻烦。
所以如何破局?
有下面三个主要的方向:
用长期有效的jwt来和服务器换取短期的jwt,只能用短期的jwt来访问非敏感资源。用长期jwt访问敏感资源且长期jwt在签发登录时绑定用户设备的指纹信息。
用redis缓存用户最新的jwt封禁时间,过期时间为长期jwt的有效,在用户重新登录,改密码,强制下线,封禁,冻结,注销等事件后将redis缓存的jwt封禁时间进行更新。
在用户利用长期jwt进行敏感操作和换取短期jwt时先进行常规的jwt校验,然后解算出用户id和颁发时间去redis找是否有jwt封禁记录,如果有查看提交的jwt是否颁发时间晚于封禁时间,如果没有找到封禁记录或者提交的jwt令牌为新的令牌则解析jwt令牌中的登录方式和敏感操作需求的授信等级是否满足,比如密码登录方式的jwt不能执行验证码登录等级的操作行为比如删除珍贵信息。在校验合格后执行操作或者返回短期jwt
这个方案的优点,实行需求分离,redis数据库只存储封禁的记录而不是有效的记录,节省内存,只在敏感操作和令牌交换时才进行redis查询,节省带宽和计算资源,用长期jwt换取短期jwt,减少用户登录的频率,用jwt自带的数据减少对数据库的读写,只能用短期jwt访问非敏感数据保证了即使长期jwt泄漏,也不会导致长期利用泄漏的长期jwt来访问非敏感资源。
这个方案的缺点就是不保证绝对安全,在短期jwt没有过期的时间内,如果短期jwt泄漏,是没有任何手段去控制他去访问非敏感资源的,还有一种情况是用户泄漏长期jwt但是不自知的情况下用jwt所在设备的原机进行操作就会非常危险,翻译成人话就是手机电脑被偷了还被正常用还不第一时间发现改密码,这种情况相当于近源攻击,这种已经和工程学设计的如何已经没啥关系了