我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

现代各种网络接口的鉴权,都离不开各种令牌token。其中,使用最普遍的就是JWT令牌,全称JsonWebToken。本文就是基于node环境,测试jwt令牌的生成与验证。当然,其它语言中也有jwt令牌的实现,并不局限于node环境。

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - jwt令牌
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:nodejs@20.18.0,JsonWebToken@9.0.2。本文的代码很简单,就是JWT令牌的生成与解密。

写在前面

现在的各种网络接口鉴权,都不走原来的session/cookie那一套理论了,都是走token令牌鉴权了。苏南大叔对这种token鉴权不太喜欢,因为:

  • 理论上来说,泄漏了token也就相当于密码丢失了。并且这是一种无状态服务,无法封杀被泄漏的令牌,在有效期结束之前,【无论是否修改密码】,这个令牌都是生效的。(除非在使用令牌的时候,再做其它逻辑)
  • 很多网络服务这种token的过期时间又很长很长,很久之后才会失效。即使修改密码的话,原token依然有效。也就是说,一旦拿到token,理论上就可以几乎“永久”劫持。
  • 令牌是可以解密的,不要放置私密信息到payload里面!没有服务器端的加密密码的话,仅仅是无法通过数据验证而已。但是,内容是可以随意解密的!

官方文档

jsonwebtoken的官方网站地址:

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - jsonwebtoken-website
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-2)

这里有很多语言版本的实现,本文是基于node环境的。苏南大叔选择的这个node环境下的jsonwebtoken实现。参考:

需要先安装jsonwebtoken。参考命令:

npm i jsonwebtoken --save

生成令牌(加密)

实际上这个令牌的生成过程,可以理解为对【目标信息】,使用一个密码进行加密的行为。它支持很多种加密算法,默认的算法是HS256。加密的时候,可以设定有效期,超过有效期的数据,会报错jwt expired。并不是说不能解密,而是说解密得到的信息是个“过期状态”。

要用来加密的数据,在这里称之为payload

const jwt = require("jsonwebtoken");
const secret = "数据验证密码sunan";         // 用于verify的密码
const payload = {
  user: "sunan大叔",                       // 真正的数据,然而它是可以无需密码就可以解密出来的
  // iat: Math.floor(Date.now() / 1000),   // 控制签发时间,当前Unix时间戳
};
const options = {
  expiresIn: "5000",       // 秒s分钟m小时h天d周w年y,大小写无关,月的写法未知,默认单位毫秒ms
  algorithm: "HS256",      // 默认算法是 HS256,会出现在令牌的header里面
  issuer: "令牌颁发者苏南", // 颁发者,会出现在令牌的payload里面
  audience: "令牌接收者sunan", // 接收者,会出现在令牌的payload里面
  // ...
};
const token = jwt.sign(payload, secret, options);
console.log(token);        // 多次加密结果保持一致

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - 生成令牌
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-3)

令牌生成时间 iat

在这里,令牌的生成时间叫做iat
通过主动设置payloadiat,可以控制生成时间为过去或者未来。但是,好像没有太大的意义。它的合法值是当前的unix时间戳,单位是秒!!!不是毫秒!!!所以要除以1000!!!

它结合expireIn时间段,可以生成一个令牌的exp属性,以控制令牌的有效期。参考:

const payload = {
  user: "sunan大叔",                       // 真正的数据,然而它是可以无需密码就可以解密出来的
  iat: Math.floor(Date.now() / 1000),      // 控制签发时间,当前Unix时间戳
};

过期时间 expireIn

过期时间expireIn的默认单位是毫秒。expireIn将叠加iat之后,将转化为payload中的exp属性。

不写任何单位的话,就会把数字单位理解为毫秒。它【不区分大小写】。由于这个特点,目前月份M的表述失效,变成了分钟m。所以,除了月份外,其它的时间点都可以正常表述。比如:秒s、分钟m、小时h、天d、周w、年y。

目前的解决方案是:月份为单位的话,就需要转化为d,或者m/s之类的进行表述。

传递令牌

传递令牌,并不是JsonWebToken的分内事情,所以这里一笔带过。

正常情况下来说,token被生成后。传递给客户端,一般被保存在localStorage里面。需要通过访问网络接口的时候,通过修改请求头里面的Authorization:Bearer <token>来进行传递。这是一个承上启下的过渡过程。

令牌解密

目前的实验配置中,多次生成令牌token,会得到一样的结果,多次“加密”结果一致。不要认为这个令牌token是多么的可靠。它是可以无密码解密的,密码仅仅影响是的数据验证部分。

令牌验证

令牌token的解密结果,并不是原版的payload数据,在其基础上增加了令牌生成时间iat,令牌过期时间expiss令牌颁发者等信息。

jwt的解密算法是:

try {
  let payload = jwt.verify(token, secretKey);
  console.log(payload);
} catch (e) {
  console.log(e.message);
}

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - 鉴定令牌
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-4)

因为存在解密失败的可能性。所以,正常来说,需要加个try{}catch(){}。令牌已过期“jwt expired”,也算一种需要被截获的错误。
如果,解析成功的话,则可以发现payload里面,除了原始数据外,还存在着:

  • iat,可定义在data里面。不定义的话,就是当前UTC时间戳。
  • exp,实际的过期时间戳,UTC【秒】级别时间戳。注意:单位是秒而不是毫秒。
  • iss,定义来自于optionsissuer属性。意思是令牌的发布者。
  • aud,定义来自于optionsaudience属性。意思是令牌的接收者。

时间可读

实际上针对的就是payload里面的iatexp。它们两个如何解读为可以正常理解的时间的话。可以参考代码:

const iat = new Date(payload.iat * 1000);
console.log(iat.toLocaleString("zh-CN"));
const exp = new Date(payload.exp * 1000);
console.log(exp.toLocaleString("zh-CN"));

令牌格式

令牌格式上分为三部分,格式是:header.payload.verify。使用.进行分割。

  • 第一部分是header,内容包括算法等信息。
  • 第二部分是payload,最重点的部分!它仅仅是个加密的结果,可以直接无密码解密!
  • 第三部分是verify部分,这个地方才用的到服务器端报错的那个secret

所以,秘密信息payload都已经被解出来了。伪造的verify部分确实无法通过服务器端验证。但是,如果这个token是被泄漏的那种呢?verify部分也是可以通过验证的。

官方解密

jwt官方提供了令牌解密的功能:

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - jwt解密
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-5)

这个官方解密界面,并不知道测试数据是使用什么secret加密的。所以,它解密出了headerpayload部分(获得了数据格式)。第三方部分verify部分是失败的。随便填入一个secret的话,它可以自动修改主界面上用来测试数据的第三部分verify部分,使它变成一个合法的token

苏南大叔:JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境 - 服务端secret的作用
JWT鉴权,JsonWebToken如何生成令牌与鉴定?Node环境(图6-6)

也就是说:
得到一个合法的token的话,就可以分析出加密算法以及payload的格式。还可以在到期之前,获得接口承认的合法身份。
一旦服务器端的secret泄漏的话,就可以批量伪造任何合法的token了。

相关文章

以前也写过其它的类似鉴权方式,参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   express