4

引言

最近学jwt学疯了,我之前很少做梦的,这两天天天做梦。

梦到自己写jwt,梦到制定http 3.0规范,梦到Github封杀我。

可能是又到了一层境界。

最近看了好多的博客去研究jwt,发现很多博客对jwt存在误解,所以我特意去jwt的官方网站去学习,试图理解设计的思想。

jwt

请移步jwt官网

jwtjson web token

与传统的SESSION认证方式不同的是,传统方式是COOKIE里面存放JSESSIONID,浏览器根据JSESSIONIDSESSION,用户信息存放在SESSION里。

jwt则不同,令牌经过解密,得到的就是用户信息,所以完全可以不用SESSION,以减轻服务器的存储压力。

jwt由三部分组成:HEADERPAYLOADSIGNATURE

HEADER

头信息包括签名算法和令牌类型。

如下数据所示,签名算法为HS256(签名算法会在后面用到),令牌类型为JWT

{
  "alg": "HS256",
  "typ": "JWT"
}

将头信息使用base64url加密,注意不是base64!两者区别:difference-between-basic-and-url-base64-encoding

在线加密网站:base64 encode online

clipboard.png

注意,为了方便阅读,将json添加换行与缩进,在标准的jwt中,需要去掉换行和空格再进行加密。

加密完成:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9jwt的头部有了。

PAYLOAD

语言的最高境界就是不用翻译,这里就不翻译了,similar to data

这部分比较自由,官方文档是这样描述的:not mandatory but recommended

mandatory大家肯定认识,这个词都用了快两年了。

iss (issuer), exp (expiration time), sub (subject), aud (audience)
{
  "iss": "yunzhi_auth_service",
  "exp": "1554453501",
  "sub": "zhangxishuo1998"
}

对此json串进行base64url加密。

base64url说解密就解密,所以不建议在数据中添加敏感信息,总不能把密码放里吧?一个用户id足矣,就像我们过去的SESSION一样。

如果觉得id不合适,那就用用户名,反正保证unique和查询效率即可,给username这一列加上索引,B+树查询相当快。

httpSession.setAttribute(TeacherService.TEACHER_ID, persistTeacher.getId());

clipboard.png

加密完成:eyJpc3MiOiJ5dW56aGlfYXV0aF9zZXJ2aWNlIiwiZXhwIjoiMTU1NDQ1MzUwMSIsInN1YiI6InpoYW5neGlzaHVvMTk5OCJ9jwt的数据有了。

SIGNATURE

因为数据是透明的,所以假如用户把用户名给改了,再base64url加密,再去访问我们的系统,那不就变成了另一个用户登陆了吗?

为了解决数据篡改问题,引入了签名机制。

后台生成一个密钥用于签名,这里密钥以yunzhi为例。

数据是HEADER + . + PAYLOAD,即:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOiJ5dW56aGlfYXV0aF9zZXJ2aWNlIiwiZXhwIjoiMTU1NDQ1MzUwMSIsInN1YiI6InpoYW5neGlzaHVvMTk5OCJ9

使用HEADER里设置的HS256算法和密钥yunzhi对数据进行签名。

这里不知道是不是我用的有问题,我用在线工具签出来的签名一直是错误的。但是我检查了好几遍,我就是和官网相同的步骤。很疑惑。

jwt官网签出来的签名是KlmSnbhfw8Q2RTB3KmOhFJcFxwzxJEcYa5osOlYP-5U

连接

HEADERPAYLOADSIGNATURE.连接在一起,就是jwt

jwteyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ5dW56aGlfYXV0aF9zZXJ2aWNlIiwiZXhwIjoiMTU1NDQ1MzUwMSIsInN1YiI6InpoYW5neGlzaHVvMTk5OCJ9.KlmSnbhfw8Q2RTB3KmOhFJcFxwzxJEcYa5osOlYP-5U

签名

这里一起研究一下签名,签名是防止数据篡改的。

因为签名需要一个密钥,这个密钥是服务器私有的,所以能保证这个签名不被伪造。只有服务器能签名。

校验时,服务器再根据自己的密钥生成签名,对比,如果一致,说明数据没有被篡改。

SSL其实也是有签名的,其实就是我们常见的HTTPS证书。

RSA非对称加密,公私钥,私钥存储再服务器中,公钥要传输给浏览器。怎么保证传输过程公钥不被篡改呢?

如果公钥被黑客篡改,那就毫无安全性可言。

为了保证公钥的安全,设计了HTTPS证书。

CA机构将公钥进行hash,生成摘要,再用自己的私钥对摘要进行签名,即生成数字签名。HTTPS证书,就是公钥+数字签名。

浏览器获取到证书,同样对公钥进行hash,生成摘要,用CA公钥对数字签名解密,如果两者一致,证明证书没有被篡改。

总结

其实学习这个有啥用呢?如果只是停留在jwthttps的使用上,那确实没什么用。

学习的是一种思想,一种前人经过无数次推敲总结出来的设计思想。

如果以后我们再碰到一个防止数据篡改的业务,有了这种思想,我们也可以设计自己的数字签名。


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。