浅析JWT
浅析JWT
随着移动互联网的兴起,传统基于session/cookie的web网站认证方式转变为了基于OAuth2等开放授权协议的单点登录模式(SSO),相应的基于服务器session+浏览器cookie的Auth手段也发生了转变,Json Web Token的出现成为了当前的热门的Token Auth机制。
Cookie和Session相关概念请见博文:Cookie-Session
Json Web Token(JWT)
Json web token (JWT) 是目前最流行的跨域认证解决方案,JWT是一个开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,可以在客户端与服务器之间作为JSON对象安全地传输信息。
官方定义:JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties
现在网上大多数介绍JWT的文章实际介绍的都是JWS(JSON Web Signature),这也往往导致了大家对于JWT的误解,但是JWT并不等于JWS,JWS只是JWT的一种实现,除了JWS外,JWE(JSON Web Encryption)也是JWT的一种实现。
下面就来详细介绍一下JWS与JWE的两种实现方式:
JSON Web Signature(JWS)
JSON Web Signature 是一个有着简单的统一表达形式的字符串。
头部(Header)
头部用于描述关于该JWT的最基本的信息,例如:Token类型以及签名所用的算法等。
JSON内容要经Base64 编码生成字符串才能成为Header。
示例
1 | { |
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 |
载荷(PayLoad)
payload的五个字段都是由JWT的标准所定义的。
- iss: 该JWT的签发者;
- sub: 该JWT所面向的用户
- aud: 接收该JWT的一方;
- exp(expires): 什么时候过期,这里是一个Unix时间戳
- iat(issued at): 在什么时候签发的,即JWT生成的时间;
还有一些其他的信息没有列举出来,也都是可以按需补充的。
JSON内容要经Base64 编码生成字符串成为PayLoad。
示例
1 | { |
对其进行base64加密,得到JWT的第二部分。
1 | eyJqdGkiOiIyOGYxNmE4YS1mMDM1LTRkYWQtYTFiNy01N2YwNzdmM2ZkZjUiLCJzdWIiOiJUZXN0IiwiaWF0IjoxNjgzMjcxOTE0LCJleHAiOjE2ODMyNzE5NzQsImF1ZCI6Ild1emkiLCJuYW1lIjoiTWFwbGUifQ |
签名(Signature)
这个部分是由base64加密后的header和base64加密后的payload,使用.连接组成的字符串,然后通过header中声明的加密方式,并使用密钥secret进行加密,生成签名。
示例
由上述base64加密的Header和PayLoad拼接并加密得到签名部分:
1 | Lu1NgVnhdlOYFBrki6HPx15X6hl8tnGB4jGWRdondNQ |
JWS的主要目的是保证了数据在传输过程中不被修改,验证数据的完整性。
上述示例得到的完整的JWT整体格式为 header.payload.signature ,具体值为:
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyOGYxNmE4YS1mMDM1LTRkYWQtYTFiNy01N2YwNzdmM2ZkZjUiLCJzdWIiOiJUZXN0IiwiaWF0IjoxNjgzMjcxOTE0LCJleHAiOjE2ODMyNzE5NzQsImF1ZCI6Ild1emkiLCJuYW1lIjoiTWFwbGUifQ.Lu1NgVnhdlOYFBrki6HPx15X6hl8tnGB4jGWRdondNQ |
JSON Web Encryption(JWE)
相对于JWS,JWE则同时保证了安全性与数据完整性。JWE由五部分组成:
具体生成步骤为:
- JOSE含义与JWS头部相同。
- 生成一个随机的Content Encryption Key (CEK)。
- 使用RSAES-OAEP 加密算法,用公钥加密CEK,生成JWE Encrypted Key。
- 生成JWE初始化向量。
- 使用AES GCM加密算法对明文部分进行加密生成密文Ciphertext,算法会随之生成一个128位的认证标记Authentication Tag。
- 对五个部分分别进行base64编码。
可见,JWE的计算过程相对繁琐,不够轻量级,因此适合数据传输而非token认证,但该协议也足够安全可靠,用简短字符串描述了传输内容,兼顾数据的安全性与完整性。
JWT的使用
一般实际开发中说的JWT,实际上都是JWS,所以下述JWT默认就是JWS。
什么是JWT?
json web token 通过数字签名的方法,以json对象为载体,在不同的服务器之间安全的传输信息。
简单来说:把信息进行安全的封装,以json的形式进行安全的网络传输。
JWT的作用?
JWT最常见的场景就是授权认证,一旦用户进行了登录操作,服务端会返回一个JWT(token)给客户端,后续客户端的每个请求都在请求头中带上JWT(token),系统在每次处理用户请求之前,都要先进行JWT安全校验,通过之后在进行处理。
用户在提交登录信息后,服务器校验数据后将通过密文的方式来生成一个字符串token返回给客户端,客户端在之后的请求会把token放在header里,在请求到达服务器后,服务器会检验和解密token,如果token被篡改或者失效将会拒绝请求,如果有效则服务器可以获得用户的相关信息并执行请求内容,最后将结果返回。
SpringCloud下如何使用JWT?
在微服务架构下,通常有单独一个服务Auth去管理相关认证,为了安全不会直接让用户访问某个服务,会开放一个入口服务作为网关gateway,所有请求首先访问gateway,由gateway将请求路由到各个服务,通常的做法在网关里进行请求拦截校验,来保证项目的安全性,下图是JWT在微服务中流程图(图中采用非对称加密算法,利用私钥在auth加密,公钥在网关gateway中解密,由此来减轻auth压力,此模型设计并不一定通用,架构设计主要根据实际场景和领域模型划分,可灵活设计并运用JWT)。
针对非对称加密严格地说:公钥加密,私钥解密;私钥加签,公钥验签。
关于JWT有效期与安全性
JWT如果使用不当,服务器如同裸奔~~~,在使用JWT是一定要注意。
假如黑客监控电脑,抓包获取到JWT,伪造HTTP请求,对服务器是非常不安全的,常见的问题如下:
- 黑客修改HTTP中body的信息进行操作 - 篡改;
- 修改body之后签名信息就不正确,然后就无法验证签名,说明数据被修改,数字签名的意义所在;
- 黑客伪造用户JWT进行访问和操作 - 伪造;
- 无法使用服务器的签名,所以在保证密钥不被泄露的情况下,不会被渗透;如果签名算法和秘钥泄露,那就是裸奔了;
- 黑客窃取JWT,模仿真实用户进行操作 - 冒充;
- 解决办法:
- 对敏感api接口,采用https,https是在http超文本传输协议加入SSL层,它在网络间通信是加密的,所以需要加密证书。
- 或者在代码层面进行优化做安全检测:比如根据ip地址,设备码,一次性token机制,token时效期等措施来解决项目安全性问题等等
- 解决办法:
JWT工具类
引入依赖
1 | <dependency> |
代码
此处只是一个Demo,在实际的开发中,还可以进行更个性化的封装,尤其是针对payload荷载部分,一般在开发中需要保存在JWT中的用户信息是一个POJO对象,而原生JWTBuilder中针对荷载部分的设置是使用 claim() 方法,用起来不是很方便,可以进行一个防腐层封装。
防腐层封装的个人思考
JWT工具类的作用范围定位是全局,甚至是可以将其封装为一个基础的二方包,所以防腐层必须具有通用性,那么就不能使用POJO类型,因为无法确定需要支持的POJO的具体类型,可以考虑使用 Properties类型 、String类型、JSON串等。
1 | import io.jsonwebtoken.*; |
测试:
1 | public static void main(String[] args) throws Exception { |
输出:
1 | jwt = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyOGYxNmE4YS1mMDM1LTRkYWQtYTFiNy01N2YwNzdmM2ZkZjUiLCJzdWIiOiJUZXN0IiwiaWF0IjoxNjgzMjcxOTE0LCJleHAiOjE2ODMyNzE5NzQsImF1ZCI6Ild1emkiLCJuYW1lIjoiTWFwbGUifQ.Lu1NgVnhdlOYFBrki6HPx15X6hl8tnGB4jGWRdondNQ |
JWT的生成特点:可以重复请求,每次请求都会生成一个新的JWT,旧JWT依旧有效。
参考文档:


