JWT 加密token 解密解码明文header和payload

该工具不会验证token,在你的代码里面请确认验证了token。

关于JWT

JSON Web Token (JWT),通常读作 “jot”,是一个定义了以 JSON 对象紧凑而自包含的在各方之间安全传输信息的标准。其包含了声明方面的信息,特别的被用于如 HTTP 等空间受约束的环境;该信息可被验证,也是可信的,因为经过了数字化签名。JWT 可以用 密钥(如 HMAC)公钥私钥对(RSA 或 ECDSA) 签名。

JWT 的两个特性是:

  • 紧凑 Compact: 因为其相对较小的尺寸,JWT 可以借由 URL 发送, 作为一个 POST 参数,或在一个 HTTP header 内。
  • 自包含 Self-contained: 一个 JWT 包含了所有关于一个实体的所需信息,以避免多次查询数据库。JWT 的接纳者同样无需调用服务器以验证令牌。

这些令牌可以是被签名的、被加密的,或两者皆有。签名过的令牌被用来验证令牌完整性,而加密过的令牌用来隐藏声明。

注意:正如名称所暗示的,JWT 是 JSON 形式的,也就意味着其包含键值对。虽说在 JSON 合法和有关方一致性方面,对键和值有多长并无限制,但大多数标准都遵循了 3个字母 的键格式。

JWT 术语

JWT 表现为由点(~.~)分割的三个字符串组成的一个序列,典型的格式看起来如下:

AAAAA.BBBBB.CCCCC

三个子串分别称作 头部(Header)负载(Payload)签名(Signature),下面逐一讲解:

头部 Header

虽说只要相关几方之间有共识,则在头部中放什么是没有限制的,但通常由两部分组成:

  1. typ: 表示令牌类型(type),值为 ~JWT~
  2. alg: 表示签名此令牌的算法(algorithm),如 ~HMAC~、~RSA~、~SHA~

负载 Payload

JWT 的第二部分表示负载,这部分由声明(claims)组成。

所谓声明就是关于实体和任意附加数据的信息。在一段 JWT 中,声明由键表示。这些声明是依赖上下文的,且应该相应的被处理和被理解,但依每种规范会有若干标准规则应用于声明:

  1. 在一个 JWT 声明集合中,每个声明的名称必须是唯一的
  2. 对于 JWT 的处理逻辑,必须 保证这种唯一性,要么拒绝重复的名字,要么用一个 JSON 处理器返回重复项中词法上最后一个名字
  3. 使用 JWT 的应用要明确其选用的声明标准,并定义必须项和可选项
  4. 因为 JWT 的核心目标之一就是精简,故所有名字也应该简短

一个可能的负载例子:

{ 
    "sub": "1234567890", "name": "Alice", "admin": true
}

负载中的声明又可以细分为以下三种类型:

已注册的声明

有一些声明注册在 IANA(dzone.com/refcardz/co…) 的 “JSON Web 令牌声明” 注册表中。这些声明并非是在所有情况下都要求强制使用或实现的,准确的说它们是作为提供一个有用的集合的起始点而被注册的。

其中一些有必要了解的是:

  1. iss (issuer): 声明了发行人,也就是发行 JWT 的主体。处理此声明通常是因应用而异的。“iss” 值是一个大小写敏感的字符串,包含一个普通字符串或者一个 URL。该声明是可选的
  2. sub (subject): 表示 JWT 的主体 (用户)。值必须要么是全局唯一的,要么在发行人上下文范围内局部唯一。处理该声明通常也是因应用而异的。“sub” 值是一个大小写敏感的字符串,包含一个普通字符串或者一个 URL。该声明是可选的
  3. aud (audience): 表示 JWT 的目标接收方。如果当该声明存在且处理该声明的一方不能通过 “aud” 的值进行自我身份验证时,则 JWT 必须被拒绝。大多数情况下,这个值是由大小写敏感的字符串(包含一个普通字符串或者一个 URL)组成的数组。该声明是可选的
  4. exp (expiration): 表示过期时间,即等于或晚于那个时刻再处理 JWT 则绝不可被接受。其值通常是以秒记的时间戳(译注:按 POSIX 中定义的 “seconds since epoch” 标准,也就是 PHP 等语言中常用的那种)。该声明是可选的
  5. nbf (not before) : 表示一个时间,即早于那个时刻再处理 JWT 则绝不可被接受。 其值通常是以秒记的时间戳。该声明是可选的
  6. iat (issued at): 表示发出 JWT 的时刻。可用于判断 JWT 的寿命。必须是一个时间戳。该声明是可选的
  7. jti (JWT ID): 为 JWT 提供一个唯一的身份识别符,其值必须难以重复,以防 JWT 被重复执行。该声明是可选的

公开声明

此类声明的名字可被 JWT 使用者任意定义。但为了预防冲突,任何新名字都应该注册在 ~IANA “JSON Web Token Claims”~ 注册表中,或将其定义为包含防冲突命名空间的 URI 等。

在任何情况下,对名字和值的定义都要考虑到合理的预防措施,以确保它们在其定义的命名空间中受控。

私有声明

这可以理解为是创建自定义声明以在应用内共享信息规格,可以是除以上两种外的任意声明名字。与公有声明不同,私有声明受制于冲突问题,要小心使用。

签名

签名先是通过对头部和负载 Base64 编码而生成,其后会与一个密钥联合,最好被头部中指定的算法签名。

签名被用于校验 JWT 的发送者是否名实相符,以及信息在传送过程中是否被更改。比如,如果创建了一个使用 HMAC SHA256 算法之令牌的签名,你会像下面这样做:

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
复制代码

一个更完整的例子

观察如下 JWT 签名:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzYXRpc2giLCJhdWQiOiJteWFwcCIsIkNVU1QiOiIxIiwiZXhwIjoxNTY2MjE0NTg1LCJpc3MiOiJhdXRoLWFwcCJ9.WknG6jiM_vAaflLnKyjlXh5BrM4MUJR9dFrVx-XE3zRVWiyXeIVzI-OomFh0vVHRwrK3-Tttg0HyKBTnCA3mSg

该签名使用了 HS512 算法编码,并包含了如下信息:

Header: { 
    "alg": "HS512", 
    "typ": "JWT"
} 
Payload: { 
    "sub": "satish", 
    "aud": "myapp", 
    "CUST": "1", 
    "exp": 1566214585, 
    "iss": "my-auth-app"
}

JWT 用例

认证

当用户使用其凭证成功登录后,一个 ID 令牌会被返回。按照 OpenID Connect (OIDC) 规范,该 ID 令牌就是一个 JWT。

授权

一旦用户登录成功,应用就可能会代表用户请求访问路由、服务、资源等。为此,将使用一个访问令牌,形式上可能就是 JWT。每个后续的请求也都包含该访问令牌。由于 JWT 开销很小,也能轻易用于跨域名访问,单点登录(SSO,Single Sign-on)广泛使用这项技术。

信息交换

由于可被签名,JWT 是一种在多方间安全传递信息的良好方式,这意味着你能确定发送者名实相符。另外,一个 JWT 结构允许你验证内容没有被篡改过。

为何使用 JWT ?

解耦

JWT 最大的优势(比之于使用内存内随机令牌的用户 session 管理)就是其使得对第三方服务器认证逻辑的代理可以:

  • 一个集中式的、内部自定义开发的认证服务器
  • 更典型的是,使用 LDAP 这种可以发出 JWT 的商业产品
  • 甚至可以使用一个纯第三方的认证提供商

认证逻辑/服务器可以从应用服务器完全分离,无需在应用间再分享密码摘要。

无状态

由于 JWT 是自包含的,且无需在内存中保持请求之间的令牌,所以应用服务器可以做到完全无状态(stateless)。认证服务器可以颁发令牌,将其发回后就立即丢弃掉。

紧凑

JSON 比 XML 简介,所以当其被编码后,一个 JWT 比 SAML 令牌更小。这使得 JWT 成为一个在 HTML 和 HTTP 环境中传送的好选择。

更安全

为了签名,JWT 可以使用一个公钥/私钥对,表现为 X.509 证书的形式。一个 JWT 也可以通过分享使用了 HMAC 算法的密钥而被对称签名。同时虽然 SAML 令牌也可以使用 JWT 这样的公钥/私钥对,但相比于签名 JSON 的简单性,想用 XML 数字签名算法签名 XML 却不会引入未知的安全漏洞是非常困难的。

更通用

因为直接映射到对象,JSON 处理器在大多数编程语言中都更常见。相反,XML 没有自然的 文档到对象 的映射。这意味着 JWT 比 SAML 更易用。

更易处理

JWT 为互联网规模而设计,意思就是其在用户设备上更易处理,特别是移动端。

JWT:要考虑到的点

除去以上说过的优缺点,JWT 标准也有其自身的问题:

  • 如果需要封锁或冻结一个用户账号,应用就不得不等待令牌过期才能完全停工。
  • 如果用户要更新密码(例如在账户劫持的情况下)且一个认证在之前已经被执行过的话,那么由之前的密码产生的令牌会在过期前持续有效。
  • 在标准实现中,没有“更新”令牌被指定。因此过期后用户将重新认证。
  • 在不违背 JWT 令牌的“无状态”方面的前提下,是不可能破坏一个令牌的,即便令牌已从浏览器被删除,它也会在过期前一直有效。

为了应对这些调整,一些 JWT 库在标准实现之上增加了一个层,并允许更新令牌机制,同时也包含一些特性如在必要情况下强制用户重新认证等。

JWT:最佳实践

在动手实现 JWT 之前,让我们了解一些最佳实践,以确保基于令牌的认证恰当地用于你的应用中。

  1. 保证安全。签名 key 应该同其他任何凭证一样被处理,并只出示给必须需要它的服务。
  2. 不要在负载中加入敏感信息。令牌被签名为难操作易解码的形式。向负载中添加最少的声明以保证性能和安全性。
  3. 给令牌设置过期时间。技术上来说,一旦令牌被签名 -- 它就是永久有效的,除非用来签名的 key 改变,或明确的设置了过期时间。这会造成隐患,所以应该有令牌的过期、撤销策略。
  4. 拥抱 HTTPS。不要向非 HTTPS 的连接发送令牌,因为那些请求可以被拦截从而连累到令牌。
  5. 考察你所有的授权用例。增加一个次要的令牌验证系统以确保令牌能从你的服务器上生成,举例来说,也许不是通用做法,但可能对实现需求是很必要的。