JSON Web Token 是什么?
JSON Web Token (JWT) 是一种开放标准(RFC 7519),它定义了一种严谨且独立的方式,用于在各方之间作为 JSON 对象安全地传输信息。此信息是已验证的、可信的,因为它是经过数字签名的。JWT 可以使用一个密钥(通过 HMAC 算法)或者一个 RSA 或 ECDSA 密钥对进行签名。
尽管 JWT 可以被加密以在各方之间提供保密性,我们仍然关注签名后的 tokens。签名 token 可以验证其中包含的声明的完整性,而加密 token 隐藏了其他地方的这些声明。当使用密钥对对令牌进行签名时,签名还证明只有持有私钥的一方才是签署它的一方。
什么时候应该使用 JSON Web Tokens?
以下场景 JSON Web Tokens 是非常适用的:
授权:这是使用 JWT 最常见的情况。一旦用户登录,每一个后续的请求将会包含 JWT,允许用户访问该 Token 允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够在不同的域中轻松使用。
信息交换:JSON Web Tokens 是在各方之间安全传输信息的好方法。因为 JWTs 可以签名。例如,使用密钥对,你就可以确认发件人说他是谁他就是谁。此外,签名是通过 header 和 payload 计算出来的,你也可以验证这些内容是否被篡改。
什么是 JSON Web Token 结构
以它严谨的形式,JSON Web Tokens 由以点(.)分隔的三部分组成,它们是:
- Header
- Payload
- Signature
由此,一个 JWT 通常如下所示。
1 | xxxxx.yyyyy.zzzzz |
我们来分解下这些不同的部分。
Header
Header 通常由两部分组成:token 的类型,即 JWT, 以及使用哪种签名算法,例如 HMAC SHA256 或者 RSA。
示例:
1 | { |
然后,这个 JSON 被 Base64Url 编码以形成 JWT 的第一部分。
Payload
Token 的第二部分是 payload,它包含了声明。声明是描述了关于一个实体(通常指用户)和额外的数据。声明分为三种类型: 注册的、公开的和私有的声明
注册声明:这是一套预定义的声明,它是不强制的而是推荐的,去通过一套有用的可互相操作的声明。它们之中有一些是: iss (issuer) 签发人, exp (expiration time)过期事件, sub (subject)主题, aud (audience) 受众以及其他的。
注意: 声明的名称只能是 3 个字符,JWT 认为这是严谨的。
公开声明:这些可以由使用 JWT 的人任意定义。但是为了避免冲突,它们应该在 IANA JSON Web Token Registry 中定义,或者定义为包含抗冲突命名空间的 URI。
私有声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公开声明
一个 Payload 可能为:
1 | { |
对 payload 进行 Base64Url 编码以形成 JSON Web Token 的第二部分。
请注意,对于已签名的 token,此信息虽然可以防止篡改,但任何人都可以读取。不要将机密信息放在 payload 或者 header 中,除非它是加密的。
签名
创建签名部分你需要获取编码后的 header、编码后的 payload、一个密钥以及在 header 中指定的算法,然后再去进行签名。
例如,如果你想使用 HMAC SHA256 算法,签名将会以如下方式创建:
1 | HMACSHA256( |
签名用于验证消息在此过程中没有更改,并且在使用私钥签名的 token 的情况下,它还可以验证 JWT 的发送者就是它所说的那个人。
拼接起来
输出的是用点分隔的三个 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更严谨。
下面展示了一个 JWT,该 JWT 具有前面的 header 和 payload,并使用密钥签名。
如果你想玩转 JWT ,想将这些概念融入到实践中,你可以使用 jwt.io Debugger 解码、验证、生成 JWTs。
JSON Web Token 是如何工作?
在验证方面,当用户使用他们的证书成功的登录后,一个 JSON Web Token 将会被返回。由于 token 是凭据,因此必须非常小心以防止出现安全问题。通常,你不应将令牌保留超过要求的时间。
由于缺乏安全性,您也不应该将敏感的会话数据存储在浏览器存储中。
无论何时,用户想要访问一个受保护的路由或资源 user agent 必须发送 JWT,通常是在 header 的 Authorization 中使用 Bearer 模式。header 中的内容看起来应该是这个样子:
1 | Authorization: Bearer <token> |
在某些情况下,这可能是一种无状态授权机制。服务器的受保护路由将检查 Authorization header 中是否存在有效的 JWT,如果存在,则允许用户访问受保护的资源。如果 JWT 包含必要的数据,则可能会减少查询数据库以进行某些操作的需要,尽管情况并非总是如此。
值得注意的是如果你通过 HTTP headers 发送 JWT,你应该避免它过大。有的服务器不能接收 headers 超过 8KB。如果你下嵌入太多的信息到 JWT 中,就像包含用户的所有权限,你需要一个替代的解决方案,例如 Auth0 Fine-Grained Authorization。
如果 token 在 Authorization header 中发送,则 Cross-Origin Resource Sharing (CORS) 不会成为问题,因为它不使用 cookie。
下图显示了如何获取 JWT 并将其用于访问 API 或资源:
应用程序或客户端向授权服务器请求授权。这是通过不同的授权流程之一执行的。例如,一个典型的 OpenID Connect 网络应用程序将会使用授权码流程 通过 /oauth/authorize 这样的终端。
当确认授权后,授权服务器会为该应用返回访问 token 。
应用程序使用访问 token 访问一个受保护的资源(比如 API)
注意,带有签名的 token, 尽管 token 不能被更改,但所有含在 token 里面的信息会暴露给用户或者他方。这意味着你不要把机密信息放到 token 中。
为什么我们应该使用 JSON Web Tokens?
对比 Simple Web Tokens (SWT) 和 Security Assertion Markup Language Tokens (SAML),我们来谈谈JSON Web Tokens (JWT)的优点。
因为 JSON 没有 XML 那么冗长,编码后它的大小就更小了,使 JWT 比 SMAL 更严谨。这让 JWT 在 HTML 和 HTTP 环境中传输是一个很好的选择。
安全方面, SWT 只能由 HMAC 算法生成的共享的密钥进行对称签名。然而,JWT 和 SAML token 可以在 X.509 认证的密钥对进行签名。与签署 JSON 的简单性相比,使用 XML 数字签名签署 XML 而不引入隐蔽的安全漏洞是非常困难的。
JSOB 在大多数的编程语言中是比较常见的,因为它们可以直接映射到对象。相反,XML 没有自然的文档到对象映射。这使得使用 JWT 比使用 SAML 断言更容易。
论使用度,JWT 应用在互联网范围内。这突出了 JSON Web token 在多个平台(尤其是移动平台)上客户端处理的便利性。
编码的 JWT 和编码的 SAML 的长度比较。
如果你想阅读更多的JSON Web Tokens 相关信息,甚至已经开始在你自己的应用中使用了,你可以阅读 Auth0 中的 JSON Web Token 引导页面。