JSON Web Token 简介
什么是 JSON Web 令牌?
JSON Web Token (JWT) 是一个开放标准 (RFC 7519),它定义了一种紧凑且自包含的方式,使用 JSON 对象在各方之间安全地传输信息。此信息可以验证和信任,因为它是数字签名的。 JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的 公钥/私钥对 进行签名。
虽然 JWT 可以加密以在各方之间提供保密性,但我们将专注于签名令牌。已经签名的 token 可以验证其中包含的声明(claims)的完整性,而加密的令牌会向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,签名还能证明只有持有私钥的一方才是签署它的一方。
什么时候应该使用 JSON Web Token?
以下是使用 JSON Web Token 的一些场景:
授权:这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够在不同的域中轻松使用。
信息交换:JSON Web Token 是在各方之间安全传输信息的好方法。因为可以对 JWT 进行签名(例如,使用公钥/私钥对),所以您可以确定发件人就是他们所说的那个人。此外,由于使用标头和有效负载计算签名,还可以验证内容没有被篡改。
JSON Web Token 结构是什么?
在其紧凑的形式中,JSON Web Token 由三部分组成,由点 (.) 分隔,它们是:
- 标题(Header)
- 有效负载(Payload)
- 签名(Signature)
因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz
让我们开始解释不同的部分。
标头(Header)
标头通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后,这个 JSON 被 Base64Url 编码以形成 JWT 的第一部分。
有效负载(Payload)
令牌的第二部分是有效负载,其中包含声明(claim)。声明是关于实体(通常是用户)和附加数据的陈述。声明分为三种类型:注册声明、公开声明和私人声明。
声明(claim):一个声明表示为一个键值对,由一个 key 和一个 value 组成。关于某个主题的一条信息。
注册声明:这些是一组预定义的声明,它们不是强制性的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:iss(发行人)、exp(到期时间)、sub(主题)、aud(受众)等。
请注意,声明的 key 只有三个字符,为了保证 JWT 的紧凑。
公共声明:这些可以由使用 JWT 的人随意定义。但是为了避免冲突,它们应该在 IANA JSON Web Token Registry 中定义,或者定义为包含抗冲突命名空间的 URI。
私有声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公共声明。
一个有效负载示例:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对有效负载进行 Base64Url 编码以形成 JSON Web Token 的第二部分。
请注意,对于已签名的令牌,此信息虽然受到保护以防篡改,但任何人都可以读取。请勿将机密信息放入 JWT 的有效负载或标头中。除非已加密。
签名
要创建签名部分,您必须获取编码的标头、编码的有效负载、密钥、标头中指定的算法,并对其进行签名。
例如,如果您想使用 HMAC SHA256 算法,签名将通过以下方式创建:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
签名用于验证消息在此过程中没有被篡改,并且在使用私钥签名的令牌的情况下,它还可以确定 JWT 的发送者是谁。
把所有的放在一起输出是三个用点分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。
下面显示了一个 JWT,该 JWT 具有先前的标头和有效负载编码,并使用秘密签名。编码的 JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
如果您想玩 JWT 并将这些概念付诸实践,您可以使用 jwt.io Debugger
来解码、验证和生成 JWT。
JSON Web 令牌如何工作?
在身份验证中,当用户使用其凭据成功登录时,将返回一个 JSON Web Token。由于 Token 是凭据,因此必须非常小心以防止出现安全问题。通常,您不应将令牌保留超过所需的时间。
由于缺乏安全性,您也不应该将敏感的会话数据存储在浏览器存储中。
每当用户想要访问受保护的路由或资源时,用户代理(user agent)应该发送 JWT,通常在 Authorization 标头中使用 Bearer 模式。标头的内容应如下所示:
Authorization: Bearer <token>
在某些情况下,这可以是一种无状态授权机制。服务器的受保护路由将检查 Authorization 标头中是否存在有效的 JWT,如果存在,则允许用户访问受保护的资源。如果 JWT 包含必要的数据,则可能会减少查询数据库以进行某些操作的需要,尽管情况并非总是如此。
请注意,如果您通过 HTTP 标头发送 JWT 令牌,则应尽量防止它们变得太大。某些服务器不接受超过 8 KB 的标头。如果您尝试在 JWT 令牌中嵌入太多信息,例如通过包含所有用户的权限,您可能需要其他解决方案,例如 Auth0 细粒度授权。
如果 token 在授权标头中发送,则跨域资源共享 (CORS) 不会成为问题,因为它不使用 cookie。
下图显示了如何获取 JWT 并将其用于访问 API 或资源:
- 应用程序或客户端向授权服务器请求授权。这是通过不同的授权流程之一执行的。
- 当授权被授予时,授权服务器向应用程序返回一个访问令牌。
- 应用程序使用访问令牌访问受保护的资源(如 API)。
请注意,使用签名 Token,Token 中包含的所有信息都会向用户或其他方公开,即使他们无法被篡改。这意味着您不应将秘密信息放入Token 中。
为什么我们应该使用 JSON Web Token?
让我们来谈谈 JSON Web Token (JWT) 与 Simple Web Token (SWT) 和安全断言标记语言令牌 (SAML) 相比的优势。
由于 JSON 不像 XML 那样冗长,因此在对其进行编码时,它的大小也更小,这使得 JWT 比 SAML 更紧凑。这使得 JWT 成为在 HTML 和 HTTP 环境中传递的不错选择。
安全方面,SWT 只能通过使用 HMAC 算法的共享密钥进行对称签名。但是,JWT 和 SAML 令牌可以使用 X.509 证书形式的公钥/私钥对进行签名。与签署 JSON 的简单性相比,使用 XML 数字签名签署 XML 而不引入隐蔽的安全漏洞是非常困难的。
JSON 解析器在大多数编程语言中都很常见,因为它们直接映射到对象。相反,XML 没有自然的文档到对象映射。这使得使用 JWT 比使用 SAML 更容易。
关于使用,JWT 用于 Internet 规模。这突出了 JSON Web 令牌在多个平台(尤其是移动平台)上客户端处理的便利性。
下图比较编码 JWT 和编码 SAML 的长度 比较编码 JWT 和编码 SAML 的长度:
参考
JSON Web Token Introduction - jwt.io
RFC 7519 - JSON Web Token (JWT) (ietf.org)