原文做者:Mikey Stecky-Efantis
原文地址:5 Easy Steps to Understanding JSON Web Tokens(JWT)
译者:命名最头疼html
在本文中, 将解释JSON Web Tokens(JWT)的基本原理以及使用他们的缘由。JWT 是确保你应用程序信任和安全的重要部分。JWT 容许以安全的方式来声明,例如用户数据。git
为了解释JWT如何工做,让咱们从一个抽象的定义开始。github
一个 JSON Web Token(JWT)是一个 JSON 对象,在 RFC7519 中定义为表示两方之间的一组信息的安全方式。该令牌由标头,有效负载和签名组成。 简单来讲,JWT 只是一个具备如下格式的字符串web
header.payload.signature
复制代码
应该注意的是,双引号字符串实际上被视为有效的 JSON 对象。算法
下面将展现实际使用 JWT 的方式和缘由,咱们将使用一个简单的例子(以下图所示),这个例子中的实体是用户,应用服务器,和认证服务器。认证服务器将提供 JWT 给用户,经过 JWT,用户能够安全的和应用服务器间进行通信。json
如今,将更深刻地研究JWT自己及其构建和认证的方式。浏览器
JWT 的头部包含有关如何计算 JWT 签名的信息,其标头是如下格式的 JSON 对象安全
{
"typ": "JWT",
"alg": "HS256"
}
复制代码
在上述 JSON 中,"typ" 键值指定了 JWT 对象,"alg"键值指定使用哪一种散列算法来建立 JWT 签名组件。在这个例子中,咱们使用 HMAC-SHA256 算法(一种使用密钥的散列算法)来计算签名(在步骤 3 中更详细地讨论)。bash
PayLoad是存储在 JWT 里的内部数据(该数据也称为 JWT 的 “声明”)。在这个例子中,认证服务器建立一个JWT 用于存储用户信息,特别是用户ID。服务器
{
"userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
复制代码
在这个例子中,咱们只将一个声明放入 payload 中,你也能够根据须要添加任意数量的声明。JWT关键信息(payload)有几种不一样的标准声明,例如 "iss" 表示 issuer,"sub" 表示 subject还有 "exp" 表示expiration time。建立 JWT 时,这些字段很是有用,可是他们是可选的,想了解更多有关 JWT 标准字段的详细信息,请参阅 JWT 上的维基百科页面。
请记住,数据的大小会影响 JWT 的总体大小,一般这不是问题,可是,JWT 太大可能会对性能产生负面影响并致使延迟。
签名的计算方式经过如下的伪代码进行表述
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
复制代码
该算法的做用是经过 base64url 对步骤1和步骤2中建立的头和关键信息(payload)进行编码。而后经过点(.)来链接两个编码字符串,构成数据 data 。在 JWT 头部使用指定的散列算法对数据字符串使用密钥进行散列,并将生成的散列数据分配给 hashedData。而后对该散列数据进行 base64url 编码以产生 JWT 签名。
在该例子中,头部和关键信息(payload)都是 base64url 编码的
// header
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
// payload
eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ
复制代码
而后,在编码头和编码关键负载(payload)中周期的加入携带密钥的应用指定签名算法,因而,咱们获得签名所需的散列数据。在该例子中,这意味着应用HS256算法,并将密钥设置为字符串 "secret",在数据字符串上获取 hashedDate 字符串,以后,经过 base64url 编码 hashedData 字符串,咱们获得如下 JWT 签名
// signature
-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
复制代码
咱们已经建立了全部的组件(3个),如今咱们能够经过它们来建立 JWT了。请记住 JWT 的结构 header.payload.signature ,咱们使用经过 base64url 编码的 header 和 payload,以及步骤 3 中签署的签名,只须要组合这些组件并经过句号(.)分隔它们。
// JWT Token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
复制代码
经过浏览器,在jwt.io上你能够尝试建立属于本身的 JWT。
回到这个例子,如今该认证服务器可以发送 JWT 给用户了。
要理解使用 JWT 的目的,并而不是经过任何的方式手段去隐藏或者模糊数据。使用 JWT 的缘由是为了证实发送的数据其实是由真实的源建立的。
如上述步骤所示,JWT 内的数据通过编码和签名而不是加密的。编码数据的目的是转换数据的结构。一方面签名数据容许数据接收器验证数据源的真实性。所以,编码和签名数据不会保护数据。另外一方面,加密的主要目的是保护数据并防止未经受权的访问。有关编码和加密之间差别的详细说明,以及有关散列如何工做的更多信息,请参阅此文章
因为 JWT 仅被签名和编码,而且因为 JWT 未加密,所以 JWT 不保证敏感数据的任何安全性。
在第三个例子中,咱们使用由 HS256 算法签名的 JWT,其中只有身份验证服务器和应用服务器知道密钥。当应用程序设置其身份认证的时候,应用服务器从身份验证服务器接收密钥。因为应用程序知道密钥,所以当用户对应用程序调用JWT 链接的 API 时,应用程序能够在 JWT 上执行与步骤 3 相同的签名算法。而后该应用程序可以验证自身经过哈希操做得到的签名与 JWT 自己获得的签名是否匹配(即,它与由认证服务器建立的 JWT 签名匹配)。若是签名匹配,这意味着 JWT 有效,表示 API 的调用是来自认证服务器的。除此以外,若是签名不匹配,则表示收到的 JWT 无效,这意味着你的应用程序正受到潜在的攻击。所以,经过验证 JWT ,应用程序在自身和用户之间添加了一层信任。
咱们了解了 JWT 是什么,如何建立和验证它们,以及如何使用它们来确保应用程序与其用户之间的信任关系。这是了解 JWT 的基础和起点。在确保应用程序中的信任和安全性难题中,JWT 只是其中之一。
应该注意的是,本文中描述的 JWT 认证设置使用的是对称密钥算法(HS256),你也能够以相似的方式设置 JWT 身份验证,除非你使用非对称算法(例如:RS256)这类算法的身份验证服务器具备密钥,而且应用程序服务器具备公钥。查看此 Stack Overflow 问题了解对称和非对称算法的差别性及其详细分类。
还应该注意,JWT 应该经过 HTTPS(而不是 HTTP)链接。HTTPS 能够有效的防止未经受权的用户经过拦截服务器和用户之间通信的方式来发送 JWT。
此外,若是你的 JWT 关键信息(payload)有一部分过时了,那么整个 JWT 将被视为无效,不能再使用了。