IdentityServer4实战 - 谈谈 JWT 的安全策略

一.前言

众所周知,IdentityServer4 默认支持两种类型的 Token,一种是 Reference Token,一种是 JWT Token 。前者的特色是 Token 的有效与否是由 Token 颁发服务集中化控制的,颁发的时候会持久化 Token,而后每次验证都须要将 Token 传递到颁发服务进行验证,是一种中心化的比较传统的验证方式。JWT Token 的特色与前者相反,每一个资源服务不须要每次都要都去颁发服务进行验证 Token 的有效性验证,该 Token 由三部分组成,其中最后一部分包含了一个签名,是在颁发的时候采用非对称加密算法(最新的JWT Token)进行数据签名的,保证了 Token 的不可篡改性,保证了安全,与颁发服务的交互,仅仅是获取公钥用于验证签名,且该公钥获取之后能够本身缓存,持续使用,不用再去交互得到,除非Token包含的 keyid 对应的 公钥没被缓存(新的),就会再次向颁发服务获取。我画了一张流程图,你们能够去查看:http://www.javashuo.com/article/p-oerarhqa-bg.htmlhtml

这里说一下我在文章说所说的名词:算法

颁发服务:即生成Token的服务。数据库

资源服务:提供给用户访问的API资源缓存

二.JWT Token 的安全问题

前言中有过叙述,JWT 类型的 Token 在验证的时候,无需依靠颁发服务来验证 Token 的有效性,是一种去中心化的验证方式,这就意味着颁发服务没法集中控制 Token。假如 Token 暴露之后,在 Token 有效期内,将会一直被人恶意使用,这时候该怎么办呢?这里主要从两个方面来说,一个是尽可能避免被恶意获取Token,一个是被恶意获取了怎么控制失效。请听下面分解。安全

1.使用 HTTPS

此种方式是避免被人获取恶意获取Token。服务器

HTTPS 在传输数据时,数据内容是加密的,能够有效避免中间人攻击,因此在使用 JWT Token 的程序建议都采用HTTPS。分布式

img

2.添加自定义Token失效机制

此种方式是被恶意获取了怎么控制失效。性能

由于 IdentityServer4 对 JWT Token,默认是没有控制失效的机制的,因此若是咱们想添加这种机制,只有咱们自定义,下一节作详细介绍。网站

三.自定义Token失效机制

1.简单黑名单模式

顾名思义,就是添加一个 Token 黑名单,这个黑名单建议存在诸如 Redis 等分布式缓存,数据库等介质,可让全部资源服务共同访问。不推荐添加在资源服务本地缓存,若是这样作,那么每次添加黑名单还须要同步到每一个资源服务。每一个资源服务在每次验证Token的时候须要查询一下黑名单,若是在黑名单里面,即 Token 无效。加密

2.进阶黑名单模式

前面小节的 【简单黑名单模式】 有一个很是大的弊端,就是每一个 Token 验证时都须要去验证是否在黑名单,正常状况下,咱们正常的Token 是占绝大多数的,若是用此种机制,那么对资源是一种很大的浪费。那么咱们须要设立一种机制,来让咱们认为 可疑 的Token进行黑名单验证,那么如何来判断Token是否可疑呢,我这里想了一种方式。

如何判断 Token 是否可疑:

咱们在生成Token的时候,能够添加自定义 Claim (身份信息单元),那么咱们能够参考网站登陆的安全机制,那么咱们能够添加一个用户ip的Claim,这样咱们生成的Token都会携带用户生成Token时的IP,咱们每次验证Token是否有效时,就能够根据客户端来源IP与Token携带的IP进行匹配,若是匹配不上,那么该Token咱们就能够认为是可疑的,从而进行黑名单的验证。

该方式相对于前面的 【简单黑名单模式】模式算是一个比较好的进阶了。

在这里,咱们还须要考虑到IP做为用户的私密信息,咱们将IP放入Token时,须要对IP进行加密。由于 JWT Token 前两部分,仅仅是 base64 Encode 而已。

Claim 详解请参考 http://www.cnblogs.com/stulzq/p/8726002.html

3.强化黑名单模式

不管是【简单黑名单模式】仍是【进阶黑名单模式】,咱们在对比黑名单时是对token进行彻底比对,这样的方式,在某些场景就存在局限性,比我想让该用户在某某时间之前颁发的Token都算做黑名单。因此咱们在判断黑名单时能够根据用户id以及token颁发时间来判断。若是让规则自动失效?咱们能够用前面设定的 token颁发时间加上咱们颁发服务设置的token有效时间就等于规则失效时间。

4.将Token添加进黑名单的方式

咱们前面设立了黑名单模式,那么咱们的Token什么时候加入黑名单呢,难道让用户说,个人 Token 被盗了,你把个人 Token加入黑名单吧,这确定不现实。咱们能够在退出登陆时,就自动往黑名单添加一条规则,采用【强化黑名单模式】添加用户id以及当前时间做为token颁发时间来验证。好比用户id1000,此用户在 2018-09-20 12:11 退出,咱们就能够添加一条规则 userid=1000,tokenissuetime=2018-09-20 12:11 ,该规则表示只要用户id为1000的而且token颁发时间小于2018-09-20 12:11的token,都被算做黑名单token。

这时有人可能会说,这个token若是仍是这个用户再次拿来使用,那仍是有效的,你这个怎么没让他失效呢?咱们设立黑名单模式就是为了不用户的还在有效期的Token被他人恶意使用。对于用户本身来讲,这个问题就可有可无了。

5.所有 Token 失效的机制。

所有Token失效的方式,目前我想了两种:

1.更换颁发服务的密钥对,而且重启全部资源服务(资源服务获取的公钥默认存在内存,重启能够丢失)。这样本来的Token在验证时,将会找不到对应的公钥,致使验签失败从而Token无效。

2.相似于前面【强化黑名单模式】的验证黑名单的方式,咱们能够在验证Token的流程中加两个配置,一个是控制这种配置是否开启的开关,一个是某个时间,规则就是若是在这个时间之前颁发Token所有算做无效Token。这种就须要资源服务支持热加载配置,从而避免重启资源服务。

我我的推荐第二种方式。

四.其余解决方案

这里的内容是根据评论整理的,我我的的想法不可能面面俱到,因此整理了一下评论里比较不错的方案:

Savorboard:

JWT 的最佳实践是遵循默认的过时策略(15分钟过时), 他可以有效的保证Token的有效性。 刷新Token是为了保证身份验证的服务端与授予令牌的客户端在访问权限方面保持一致,好比Claim里可能包含最新的访问权限,这是一个必要且必须的过程。

因此,频繁的15分钟刷新令牌是有必要的,这并不足以对服务器的性能产生很大的影响。

五.写在最后

文中所诉是总结了我长久以来的想法,token加入ip还有根据id和颁发时间验证黑名单都是我今天无心间想到的。若是你阅读了本文有什么不明白或者你认为有改进的地方,或者更好的地方,欢迎在评论与我交流。本文的问题,有不少人问过我,也讨论了很多,我相信不少人在使用ids4是可能会有这样的问题,因此在此发表了个人一个观点,但愿能给你参考,后续的文章我会根据这个想法来实现。

相关文章
相关标签/搜索