JWT的简单介绍

发布于 2019-06-11  71 次阅读


JWT的简单介绍

JSON Web Token,简称 JWT,读音是 [dʒɒt]( jot 的发音),是一种当下比较流行的「跨域认证解决方案」

JWT的组成

一个 JWT token 是一个字符串,它由三部分组成,头部载荷签名,中间用 . 分隔,例如:xxxxx.yyyyy.zzzzz
header.payload.signature 如下示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

头部(header)

这部分用来描述 JWT 的元数据,比如该 JWT 所使用的签名 / 加密算法、媒体类型等。

这部分原始数据是一个 JSON 对象,经过 Base64Url 编码方式进行编码后得到最终的字符串。其中只有一个属性是必要的:alg—— 加密 / 签名算法,默认值为 HS256

最简单的头部可以表示成这样:

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

typ,描述 JWT 的媒体类型,该属性的值只能是 JWT,它的作用是与其他 JOSE Header 混合时表明自己身份的一个参数(很少用到)。

载荷(Payload)

载荷中放置了 token 的一些基本信息,以帮助接受它的服务器来理解这个 token。同时还可以包含一些自定义的信息,用户信息交换。

{
  "sub": "1",
  "iss": "http://localhost:8000",
  "iat": 1451888119,
  "exp": 1454516119,
  "nbf": 1451888119,
  "jti": "37c107e4609ddbcc9c096ea5ee76c667",
  "aud": "dev"
}
  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主体
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

载荷中有两个比较重要的数据,exp 是过期时间,sub 是 JWT 的主体,这里就是用户的 id

JWT 最后是通过 Base64 编码的,也就是说,它可以被翻译回原来的样子来的。所以不要在 JWT 中存放一些敏感信息

签名(Signature)

  • 签名时需要用到前面编码过的两个字符串,如果以 HMACSHA256 加密,就如下:
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

加密后再进行 base64url 编码最后得到的字符串就是 token 的第三部分 zzzzz
组合便可以得到 token:xxxxx.yyyyy.zzzzz

签名的作用:保证 JWT 没有被篡改过,原理如下:

HMAC 算法是不可逆算法,类似 MD5 和 hash ,但多一个密钥,密钥(即上面的 secret)由服务端持有,客户端把 token 发给服务端后,服务端可以把其中的头部和载荷再加上事先共享的 secret 再进行一次 HMAC 加密,得到的结果和 token 的第三段进行对比,如果一样则表明数据没有被篡改。
Hash-based Message Authentication Code

JWT 相对于一般 token 的优点

无状态

因为 JWT 的有效期完全与其载荷中编码的过期时间,服务端不维护任何状态,因此 JWT 『一般』是『无状态』的(为什么是一般,后面会仔细说)。无状态最大的优势在于三点:
- 节省服务器的资源:因为服务端无需维护一个状态,因此能够节省服务端原先保存这些状态所花费的资源

  • 适合分布式:因为服务端无需维护状态,因此如果服务端是多台服务器组成的分布式集群,那么无需像『有状态』一样互相同步各自的状态。

  • 时间换空间:因为 token 的校验时通过签名校验来进行的,签名校验消耗的是 CPU 时间,而『有状态』是需要通过客户端提供的凭据对服务端现有的状态进行一次查询,消耗的是 I/O 和内存、磁盘空间。通常对于一个 Web 服务来说,其属于 I/O 密集型,因此通过时间换空间这一操作,可以提高整体的硬件使用率。

编码数据

因为 JWT 能够在载荷中编码了部分信息,所以如果把常用数据编码进去的话,能够大大减少数据库的查询次数,不过有两点需要额外注意的:

  • 载荷信息是明文编码的,所以不能编码敏感信息在里面,如果要编码可以先加密再编码进去
  • token 在每次请求时都会进行传输,所以载荷中不能编码过多的信息,否则会降低传输效率

所以 JWT 就有四个优点了:

  • 防 CSRF
  • 适合移动应用
  • 无状态
  • 编码数据
  • 前两个是 token 的优势,后两个是 JWT 独特的优势。

JWT 交互时的方式

  • 加到 url 中:?token=你的token
  • 加到 header 中,建议用这种,因为在 https 情况下更安全:Authorization:Bearer 你的token

更推荐后者

JWT 在客户端的存储有三种方式:

  • LocalStorage
  • SessionStorage
  • Cookie [不能设置 HTTPonly]

但是最推荐的还是第三种,因为第一二种存在跨域读取限制,而 Cookie 使用不同的跨域策略

JWT Cookie存储的安全性

Cookies,当使用带有HttpOnly的cookie标志时,通过JavaScript是无法访问的,并且对XSS是免疫的。你还可以设置安全的cookie标志来保证cokie仅通过HTTPS发送。这是过去利用cookie存储令牌或会话数据的主要原因之一。现代开发人员不愿使用cookie,因为它们通常要求状态被存储在服务器上,从而打破RESTful的最佳实践。如果你在cookie上存储JWT,cookie作为存储机制不用将状态存储在服务器上。这是因为JWT封装了所有服务器需要服务的请求。

下篇讲一下TP5.1使用JWT


还是好热爱web开发