logo

[译] JSON Web Token Intro

什么是 JSON Web Token?

JSON Web Token(JWT)定义了一个紧凑独立的开放标准(RFC 7519),通过一个 JSON 对象来安全的传输数据。这些数据是可信的因为它们经过数字签名的。JWTs 可以使用一个密钥(使用 HMAC 算法)或 RSA 的公/私匙对来进行签名。

虽然 JWTs 可以被加密为通信提供隐秘性,但是我们只关注于签名令牌(signed tokens)。签名令牌可以验证声明内容的完整性,但是加密 JWTs 会隐藏声明内容。当 JWTs 使用公/私钥对加密后,那么只有拥有私钥的一方能够验证其有效性。

让我们来进一步阐述一些概念。

  • 紧凑性,为了更小的体积,JWTs 可以通过 URL,HTTP POST 参数或 HTTP Header 进行传输。另外,更小的体积意味着更快的传输速度。

  • 独立性,JWTs 的载荷中包含了关于用户的全部信息,避免多次查询数据库。

什么情况下我们应该使用 JSON Web Tokens?

这里有一些 JSON Web Tokens 的适用场景:

  • 认证:这是使用 JWT 最常见的场景。一但用户登录后,之后用户的请求将都包含 JWT,用户可以访问令牌权限范围内的路由,服务,资源。单点登录是 JWT 现在被使用最多的一个特性,因为它开支小,可以在多个不同的域名中使用。

  • 信息交换:JOSN Web Tokens 是进行安全通信的不错的方法。因为它是可以被签名认证 —— 例如公私钥对,你可以确定发送者的身份。另外,签名是通过其 header 和载荷计算生成的,可以验证内容以确保内容不被篡改。

JSON Web Tokens 的结构是什么样的?

在它紧凑的格式中,JSON Web Tokens 由三部分组成使用(.)隔开:

  • Header,头部
  • Payload,载荷
  • Signature,签名

因此一个典型的 JWT 格式如下。

1
xxxxx.yyyyy.zzzzz

然我们来分解成不同部分介绍。

头部(Header)

头部通常包含两部分,令牌(token)类型值为 JWT,使用的 hash 算法(例如,HMAC SHA256 or RSA)。

例子:

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

然后,首部通过 Base64Url 转码为 JWT 的第一部分。

载荷(Payload)

令牌(token)的第二部分是载荷,包含了声明。声明包含了实体(通常是用户)和一些附加的元数据。声明包含三种类型: 内置(registered),公有(public),私有(private)。

  • 内置声明:其包含一系列预定义声明,不强制但是推荐使用来提供有用的,可协作性的的声明。部分如下:
    iss(issuer),exp(expiration time),sub(subject),aud
    (audience)和其他声明

注意这些声明为了和 JWT 的紧凑理念相一致,因此声明名都是三个字符。

  • 公有声明: 这部分可以由 JWTs 的使用者定义,但是注意避免冲突,应当在IANA JSON Web Token Registry中有定义,或者定义为包含命名空间(避免冲突)的 URI。

  • 私有声明: 这部分定义的声明的是双方验证同意共享信息而创建的声明,不包含在内置或共有声明中。

例如一个载荷可以如下:

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

载荷被 Base64Url 转码作为 JSON Web Tokens 的第二部分。

1
注意对于签名令牌,虽然他们被保护防止被篡改,但是对任何人都是可读的。不要将密钥放置在载荷头部中除非签名令牌是加密的。

签名(Signature)

为了创建签名我们需要转码的头部,转码的载荷,一个密钥(secret)。通过头部声明的加密算法生成签名。

例如如果你想使用 HMAC SHA256 算法,签名可以通过如下方法生成:

1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);

这个签名可以用于校验传输内容不被修改,而且由于令牌通过一个私有密钥签名,我们可以验证发起请求的用户和 JWT 中用户是否一致。

放在一起

最终得到的是 3 个以(.)隔开的 Base64-URL 字符串,可以轻松通过 HTML,HTTP 运行环境,相比 XML-based 标准如 SAML 更加紧凑。

下面是一个头部载荷转码,使用加密签名的的 JWT。

如果你想玩玩 JWT,练习其中的各种概念,你可以使用jwt.io Debugger来转码,验证,生成 JWTs。

JSON Web Tokens 是如何工作的?

在身份验证中,当用户身份验证成功后,将返回一个 JSON Web Token 并且需要保存在本地(如本地存储,cookie),代替传统的创建一个绘画并返回一个 cookie。

出于安全性考虑需要注意令牌的存储方式,它们枚举在Where to Store Token

无论什么时候用户想要访问受保护的路由或者资源,用户客户端必须发送 JWT,常见的是在 HTTP Autorization 的 Bearer 协议。
内容如下:

1
Authorization: Bearer <token>

这是一种无状态验证机制,用户的状态不会保存在服务器内存中。服务器可以在 HTTP Authorization 校验 JWT,通过校验则可以访问受保护的资源。正因为 JWT 是独立的,所有需要的信息都包含在其中,减少多次查询数据库。

JWTs 允许你完全依赖无状态数据 API,甚至请求下游服务。那些域为你的 API 提供服务并不重要,因此跨域资源共享(CORS)不会成为问题因为他们可以不使用 Cookie。

下面的图展示了整个过程:

对于签名令牌,需要注意所有信息都包含在令牌中并且这些信息是公开暴露的,虽然他们不能篡改它。意味着不要在令牌中存储密钥信息。

为什么我们使用 JSON Web Tokens?

让我们来谈谈 JSON Web Tokens(JWT) 的优点相对于 Simple Web Tokens(SWT)Security Assertion Markup Language Tokens(SAML)

JSON 数据比 XML 更加简洁,转码后体积依然更小,着使得 JWT 比 SAML 更加紧凑。这使得 JWT 在 HTML,HTTP 环境中传递成为了一种更好的选择。

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

JSON 解析器在大多数编程语言中很普及,因为它直接映射了一个对象。相反的,XML 并不含有原生的 document-to-object(文档到对象)的映射。这使得 JWT 比 SAML 更加容易运作。

至于用法,JWT 可以在互联网范围内使用,突出的是在多个客户端平台处理 JSON Web Token 的简易性,特别是移动端。

如果你想了解更多 JSON Web Tokens 甚至开始在你的应用中使用它进行身份验证,在 Auth0 浏览JSON Web Token 落地页面