1.jwt使用评价


http://www.andaily.com/blog/?s=nimbus-jose-jwt

从易用性, 扩展性, 完整性等来看, 使用首先推荐 jose4j, 其次是 Nimbus-jose-jwt.

2.概述以及官方文档

JWT是一种紧凑且自包含的,用于在多方传递JSON对象的技术。传递的数据可以使用数字签名增加其安全行。可以使用HMAC加密算法或RSA公钥/私钥加密方式。
紧凑:数据小,可以通过URL,POST参数,请求头发送。且数据小代表传输速度快。
自包含:使用payload数据块记录用户必要且不隐私的数据,可以有效的减少数据库访问次数,提高代码性能。
JWT一般用于处理用户身份验证或数据信息交换。
用户身份验证:一旦用户登录,每个后续请求都将包含JWT,允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小,并且能够轻松地跨不同域使用。
数据信息交换:JWT是一种非常方便的多方传递数据的载体,因为其可以使用数据签名来保证数据的有效性和安全性。


https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1


3.使用场景

Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

用户提供用户名和密码,我们去数据库查询一下是否匹配,如果匹配了我们就签发token,用户得到token以后可以找一个地方存起来,比如存储浏览器cookie等等,下回用户请求接口时候需要提供token, 后台代码验证token对不对,看看是不是自己签发的,token里面包含的数据可以确定用户是谁,包含了什么权限等等,然后再确定给用户提供对应的权限的资源响应数据等等,token的格式,生成验证的方法可以使用jwt等等


身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

4.它是如何做身份验证的?

首先,JWT 的 Token 相当是明文,是可以解密的,任何存在 payload 的东西,都没有秘密可言,所以隐私数据不能签发 token。
而服务端,拿到 token 后解密,即可知道用户信息,例如本例中的uuid
有了 uuid,那么你就知道这个用户是谁,是否有权限进行下一步的操作。

5.jwt工作流程


在身份验证中,当用户成功登录系统时,授权服务器将会把 JSON Web Token 返回给客户端,用户需要将此凭证信息存储在本地(cookie或浏览器缓存)。当用户发起新的请求时,需要在请求头中附带此凭证信息,当服务器接收到用户请求时,会先检查请求头中有无凭证,是否过期,是否有效。如果凭证有效,将放行请求;若凭证非法或者过期,服务器将回跳到认证中心,重新对用户身份进行验证,直至用户身份验证成功。以访问 API 资源为例,下图显示了获取并使用 JWT 的基本流程:
jwt概念 - 图1

6.优缺点

JWT相比于Session的优点:
我们就来对比,传统的 session 和 JWT 的区别
我们以一个用户,获取用户资料的例子
传统的 session 流程
1. 浏览器发起请求登陆
2. 服务端验证身份,生成身份验证信息,存储在服务端,并且告诉浏览器写入 Cookie
3. 浏览器发起请求获取用户资料,此时 Cookie 内容也跟随这发送到服务器
4. 服务器发现 Cookie 中有身份信息,验明正身
5. 服务器返回该用户的用户资料
JWT 流程
1. 浏览器发起请求登陆
2. 服务端验证身份,根据算法,将用户标识符打包生成 token, 并且返回给浏览器
3. 浏览器发起请求获取用户资料,把刚刚拿到的 token 一起发送给服务器
4. 服务器发现数据中有 token,验明正身
5. 服务器返回该用户的用户资料


但实际上区别大了去了



不占用服务器内存开销:session需要保存在服务器,因此会占用服务器内存开销(尽管JWT会让服务器有一些计算压力,比如token的签名和验证).
可扩展性强: 比如有3台机器(A、B、C)组成服务器集群,若session存在机器A上,session只能保存在其中一台服务器,此时你便不能访问机器B、C,因为B、C上没有存放该Session,而使用token就能够验证用户请求合法性,并且我再加几台机器也没事,所以可拓展性好就是这个意思。
前后端分离,支持跨域访问


登录成功之后jwt生成的token每次都是新的加密后的字符串.


JWT的缺点:

有优点就会有缺点,是否适用应该考虑清楚,而不是技术跟风

1. token中不能保存私密敏感信息:Head和Payload使用base64进行编码
2. 无法作废已颁布的token:由于所有的认证信息都在JWT中,即使你知道了某个JWT被盗取了,你也没有办法将其作废。在JWT过期之前(你绝对应该设置过期时间),你无能为力.
3. 严重依赖于密钥:JWT生成与解析过程都需要依赖于密钥(Secret),且都是以硬编码的方式存在于系统中(也有放在外部配置文件中的),如果密钥不小心泄露了,系统的安全性将受到威胁.
4. JWT不是 session ,勿将token当session,服务端无法管理客户端的信息:如果用户身份发生异常(信息泄露,或者被攻击),服务端很难向操作 Session 那样主动将异常用户进行隔离。
5. 服务端无法主动推送消息:服务端由于是无状态的,他将无法使用像 Session 那样的方式推送消息到客户端,例如过期时间将至,服务端无法主动为用户续约,需要客户端向服务端发起续约请求。
6. 冗余的数据开销:一个 JWT 签名的大小要远比一个 Session ID 长很多,如果你对有效载荷(payload)中的数据不做有效控制,其长度会成几何倍数增长,且在每一次请求时都需要负担额外的网络开销。
7. JSON Web Token 很流行,但是它相比于 Session,OIDC(OpenId Connect)等技术还比较新,支持 JSON Web Token 的库还比较少,而且 JWT 也并非比传统 Session 更安全,他们都没有解决 CSRF 和 XSS 的问题。因此,在决定使用 JWT 前,你需要仔细考虑其利弊。

7.jwt如何防止令牌泄密导致的系统安全

如果单纯的依靠 JSON Web Token 解决用户认证的所有问题,那么系统的安全性将是脆弱的。由于 JWT 令牌存储于客户端中,一旦客户端存储的令牌发生泄露事件或者被攻击,攻击者就可以轻而易举的伪造用户身份去修改/删除系统资源,岁如按 JWT 自带过期时间,但在过期之前,攻击者可以肆无忌惮的操作系统数据。通过算法来校验用户身份合法性是 JWT 的优势,同时也是最大的弊端——它太过于依赖算法。
反观传统的用户认证措施,通常会包含多种组合,如手机验证码,人脸识别,语音识别,指纹锁等。用户名和密码只做用户身份识别使用,当用户名和密码泄露后,在遇到敏感操作时(如新增,修改,删除,下载,上传),都会采用另外的方式对用户的合法性进行验证(发送验证码,邮箱验证码,指纹信息等)以确保数据安全。
与传统的身份验证方式相比,JWT 过多的依赖于算法,缺乏灵活性,而且服务端往往是被动执行用户身份验证操作,无法及时对异常用户进行隔离。那是否有补救措施呢?答案是肯定的。接下来,将介绍在发生令牌泄露事件后,如何保证系统的安全。

不管是基于 Sessions 还是基于 JSON Web Token,一旦密令被盗取,都是一件棘手的事情。接下来,将讲述基于 JSON Web Token 的方式发生令牌泄露是该采取什么样的措施(解决方案包含但不局限与本文所涉及的内容)。

为了防止用户 JWT 令牌泄露而威胁系统安全,你可以在以下几个方面完善系统功能:

清除已泄露的令牌:此方案最直接,也容易实现,你需将 JWT 令牌在服务端也存储一份,若发现有异常的令牌存在,则从服务端令牌列表中将此异常令牌清除。当用户发起请求时,强制用户重新进行身份验证,直至验证成功。对于服务端的令牌存储,可以借助 Redis 等缓存服务器进行管理,也可以使用 Ehcache 将令牌信息存储在内存中。
敏感操作保护:在涉及到诸如新增,修改,删除,上传,下载等敏感性操作时,定期(30分钟,15分钟甚至更短)检查用户身份,如手机验证码,扫描二维码等手段,确认操作者是用户本人。如果身份验证不通过,则终止请求,并要求重新验证用户身份信息。
地域检查:通常用户会在一个相对固定的地理范围内访问应用程序,可以将地理位置信息作为一个辅助来甄别用户的 JWT 令牌是否存在问题。如果发现用户A由经常所在的地区 1 变到了相对较远的地区 2 ,或者频繁在多个地区间切换,不管用户有没有可能在短时间内在多个地域活动(一般不可能),都应当终止当前请求,强制用户重新进行验证身份,颁发新的 JWT 令牌,并提醒(或要求)用户重置密码。
监控请求频率:如果 JWT 密令被盗取,攻击者或通过某些工具伪造用户身份,高频次的对系统发送请求,以套取用户数据。针对这种情况,可以监控用户在单位时间内的请求次数,当单位时间内的请求次数超出预定阈值值,则判定该用户密令是有问题的。例如 1 秒内连续超过 5 次请求,则视为用户身份非法,服务端终止请求并强制将该用户的 JWT 密令清除,然后回跳到认证中心对用户身份进行验证。
客户端环境检查:对于一些移动端应用来说,可以将用户信息与设备(手机,平板)的机器码进行绑定,并存储于服务端中,当客户端发起请求时,可以先校验客户端的机器码与服务端的是否匹配,如果不匹配,则视为非法请求,并终止用户的后续请求。

8.Token 的过期时间怎么确定?


payload 中有个标准字段 exp,明确表示了这个 token 的过期时间.
服务端可以拿这个时间与服务器时间作对比,过期则拒绝访问。

//token 就是jwt生成的token
DecodedJWT jwt = JWT.decode(token);
Map claims = jwt.getClaims();
Claim exp = claims.get(“exp”);
Date date = exp.asDate();
//获取到过期时间了
System.out.println(“date = “ + date);


9.如何防止 Token 被串改?

此时 signature字段就是关键了,能被解密出明文的,只有header和payload
假如黑客/中间人串改了payload,那么服务器可以通过signature去验证是否被篡改过。
在服务端在执行一次 signature = 加密算法(header + “.” + payload, 密钥);, 然后对比 signature 是否一致,如果一致则说明没有被篡改。
所以为什么说服务器的密钥不能被泄漏。
如果泄漏,将存在以下风险:
客户端可以自行签发 token
黑客/中间人可以肆意篡改 token


安全性相关
如果加强 JWT 的安全性?
根据我的使用,总结以下几点:
缩短 token 有效时间
使用安全系数高的加密算法
token 不要放在 Cookie 中,有 CSRF 风险
使用 HTTPS 加密协议
对标准字段 iss、sub、aud、nbf、exp 进行校验
使用成熟的开源库,不要手贱造轮子
特殊场景下可以把用户的 UA、IP 放进 payload 进行校验(不推荐)