JWT作为一种用户认证方案已经越来越广泛地应用在开发中,尤其在单点登录(Single Sign On)的场景中有其自身的优势。

什么是JSON Web Token?

JSON Web Token(JWT)是一种开放的标准,它定义了一种紧凑且独立的方式,以便在各方之间以JSON对象来安全地传输信息。因为这些信息经过数字签名,所以可以被认证和信任。JWT可以使用秘钥(HMAC算法)或者使用RSA或ECDSA的公钥/私钥对进行签名。

虽然JWT可以被加密以在各方之间提供保密,但我们仍然聚焦于签名令牌。签名令牌可以验证其中包含声明的完整性,而加密令牌对其他方则隐藏这些声明。当令牌通过公钥/私钥对进行签名,这个签名也可以验证私钥的唯一持有方,也是对其签名的一方。

什么时候应该使用JSON Web Token?

这里有一些JWT使用的场景:

  • 授权:这是JWT最常使用的场景。用户一旦登录,每一个后续请求都将包含JWT,允许用户访问令牌允许的访问的路由、服务、资源。现在单点登录是一个广泛使用JWT的功能,因为他的开销小,并且可以轻松应对跨域。

  • 信息交换:JSON Web Token是一种很好的在各方之间安全传输信息的方式。因为JWT可以签名–例如,通过使用公钥/私钥对,你可以确定发件人是谁。另外,由于签名是使用header和payload计算出来的,所以你可以确认内容没有别篡改。

JSON Web Token结构是什么样?

在JWT紧凑的结构中,三个部分通过点‘.’分隔开来,三个部分是:

  • Header
  • Payload
  • Signature

所以,JWT通常以这种形式出现: xxxxx.yyyyy.zzzzz

让我们来详细分解不同的部分。

Header
header通常由两部分组成:令牌类型和签名算法。例如:

1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}

然后,JSON经过Base64Url编码形成JWT的第一部分。

由于JWT可以直接作为链接的一部分使用,所以这里使用了Base64Url编码,将编码后可能出现的一些链接禁用字符转化为对应的字符。

Payload
令牌的第二部分是payload,包含各种声明。声明是一些关于实体(通常是用户)和额外数据的语句。有三种类型的声明:注册、公共、私密声明

  • 注册声明:这是一组非强制性但推荐的预定义声明,提供一组有用,可操作的声明。其中一些是:iss(issuer),exp(expiration time),sub(subject),aud(audience)等。

注意,声明名称只有三个字符,因为JWT是紧凑的。

  • 公共声明:由JWT的使用者按照意愿来定义。但是为了避免冲突,声明应该在IANA JSON Web Token Registry中定义过,或者被定义为包含抗冲突命名空间的URI。

  • 私密声明:这些是创建的自定义声明,可以在同意使用它们的各方之间共享信息,这些声明既不是注册声明也不是公开声明。

payload例子如下:

1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

payload经过Base64Url编码形成JWT的第二部分。

请注意,已签名的令牌虽然可以防止篡改,但是可以被任何人读取。所以除非加密,不要将机密信息放在JWT的payload或header元素中

Signature
要创建签名部分,你必须获取编码过的header,编码过的payload,秘钥,header中指定的算法,然后进行签名。
例如,如果你想使用HMAC SHA256算法,签名将会通过下面的方式创建:

1
2
3
4
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

签名被用来确认信息一直没有被改变,并且在令牌使用私钥签名的场景中,可以验证JWT的发送者是否就是他所说的那个人。

组合在一起
结果是三个由点分隔的Base64Url编码过的字符串组成,JWT可以很容易地在HTML和HTTP环境中传递,和XML-based标准(如SAML)相比,JWT更紧凑。

JSON Web Token 如何工作?

在身份验证中,当用户使用身份凭证成功登录时,将会返回一个JSON Web Token。因为令牌是登录凭证,所以必须非常小心避免安全问题。通常,你不应该让令牌的有效期超过所需的时间。

由于缺乏安全性,你也不应该将敏感的会话数据存储在浏览器存储中。

任何时候用户想要访问受保护的路由或者资源,用户代理应该发送JWT,JWT通常在请求的头部Authorization字段中,使用Bearer模式。如下:

1
Authorization: Bearer <jwt token>

在某些情况下,可以是无状态授权机制。服务端受保护的路由将会检查请求头部JWT的有效性,如果有效,用户将被允许访问受保护的资源。如果JWT包含必要的信息,可以减少某些操作查询数据库的需要,尽管这种情况并不总出现。

如果令牌在请求头部的Authorization中被发送,那么跨域资源分享将不会是一个问题,因为他不是用cookies。

下图展示了JWT如何获取并访问API或资源:

  1. 应用或客户端向授权服务器请求授权。这通过不同的授权流程的其中一个进行的。
  2. 当获取授权后,授权服务器将会向应用返回一个访问令牌。
  3. 应用通过访问令牌来访问受保护的资源(例如API)。

请注意,在使用签名令牌时,令牌中包含的所有信息都会暴露给用户和各方,即使他们无法修改相关信息。这意味着你不应该在令牌中放置加密信息。

为什么要使用JSON Web Token?

让我们来讨论一下JWT相对SWT(Simple Web Tokens)和SAML(Security Assertion Markup Language Tokens)的优势。

因为JSON没有XML冗长,当它编码后大小也更小,所以使得JWT比SAML更紧凑。这使得JWT成为在HTML和HTTP环境中传递的一个好的选择。

安全方面,SWT只能使用HMAC算法通过共享秘钥进行对称签名。然而,JWT和SAML令牌可以使用X.509证书形式的公钥/秘钥对进行签名。与签名 JSON 的简单性相比,在不引入隐藏的安全漏洞的情况下使用 XML 数字签名签署 XML 是非常困难的。

JSON解析在大多数的编程语言中都是常见的,因为他们直接映射到对象。相反地,XML没有自然的文档到对象的映射。这使得JWT相比SAML更加简单。

关于使用,JWT 用于互联网规模。这突出了客户端在多个平台(尤其是移动平台)上处理JWT的简便性。

原文:Introduction to JSON Web Tokens