JWT 是什么?
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方法,用于在各方之间安全地将信息作为JSON对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。可以使用密钥(使用HMAC算法)或使用RSA或ECDSA的公用/专用密钥对对JWT进行签名。
尽管可以对JWT进行加密以在各方之间提供保密性,但我们将重点关注已签名的令牌。签名的令牌可以验证其中包含的声明的完整性,而加密的tokens则将这些声明隐藏在其他方的面前。当使用公钥/私钥对对token进行签名时,签名还证明只有持有私钥的一方才是对其进行签名的一方。
什么时候需要使用JWT ?
有如下几个场景使用JWT是有帮助的:
授权:这是JWT的最常见使用场景。一旦用户登录,后续每个请求将携带JWT,从而允许用户访问该token允许的路径,服务和资源。单一登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域名中轻松使用。
信息交换:JWT是在各方之间安全传输信息的一种好方法。因为可以对JWT进行签名(例如,使用公钥/私钥对),所以您可以确定发送人是他们自己。此外,由于签名是使用header和payload计算的,因此您还可以验证内容是否被篡改。
JWT结构是什么 ?
JWT 以紧凑的形式由三部分组成,这些部分由点(.)分隔,分别是:
Header
Payload
Signature
典型的JWT如:xxxxx.yyyyy.zzzzz
Header
Header包含两部分, token类型,值为JWT,签名算法,如HMAC SHA256 或 RSA。例如:
{
"alg": "HS256",
"typ": "JWT"
}
复制
Header JSON使用Base64Url 编码作为JWT的第一部分。
Payload
JWT第二部分是负载,其中包含claims。claims是有关实体(通常是用户)和其他数据的声明。共有三种类型的claims:注册,公有和私有声明。
注册声明:这些是一组非强制性的但建议使用的预定义声明,以提供一组有用的,可交换信息的声明。其中一些是:iss(发行者),exp(到期时间),sub(主题),aud(受众)等。请注意,声明名称仅使用三个字符是为了使JWT紧凑。
公有声明:这些可以由使用JWT的人员随意定义。但是为避免冲突,应在IANA JSON Web Token注册表中定义它们,或将其定义为包含抗冲突名称空间的URI。
私有声明:这些是自定义声明,旨在在同意使用它们的各方之间共享信息,既不是注册声明也不是公共声明。
Payload 结构如下:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
复制
Payload 使用Base64Url 编码作为JWT的第二部分。请注意,对于已签名的Token,此信息尽管可以防止篡改,但任何人都可以读取。除非将其加密,否则请勿将机密信息放入JWT的Payload 或Header元素中。
Signature
要创建签名部分,您必须获取编码的Header,编码的Payload 和一个密钥,使用Header中指定的算法对其进行签名。
例如使用 HMAC SHA256算法,signature 创建类似如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
复制
签名用于验证消息在此过程中是否未被更改,并且对于使用私钥进行签名的Token,它还可以验证JWT的发送者是他本人。
JWT 如何工作?
在身份验证中,当用户使用其凭据成功登录时,将返回JWT。由于Token是凭据,因此必须格外小心以防止安全问题。通常,Token的保留时间不应超过需要的时间。由于缺乏安全性,您也不应该将敏感的会话数据存储在浏览器中。
每当用户想要访问受保护的路径或资源时,用户代理通常应使用Bearer 模式在Header Authorization 中发送JWT。header 的内容应如下所示:
Authorization: Bearer <token>
复制
在某些情况下,这可以是无状态授权机制。服务器的受保护路径将在Authorization header中检查有效的JWT,如果存在,则将允许用户访问受保护的资源。如果JWT包含必要的数据,则可以减少查询数据库中某些操作的需求。如果Token是在 Authorization Header中发送的,则可以支持跨域资源共享(CORS)。
下图显示了如何获取JWT并将其用于访问API或资源:
(1)应用程序或客户端向授权服务器请求授权。这是通过一个简单的授权流程执行的。例如,一个典型的符合OpenID Connect的Web应用程序将使用授权代码流程通过/oauth/authorize端点。
(2)授予认证后,授权服务器会将access token返回给应用程序。
(3)应用程序使用access token访问受保护资源。
请注意,使用签名的Token,Token中包含的所有信息都会暴露给用户或其他方,即使他们无法更改它。所以不应将机密信息放入Token中。
为什么我们需要使用JWT?
由于JSON没有XML那么冗长,因此在编码时JSON的大小也较小,从而使JWT比Security Assertion Markup Language Tokens (SAML)更为紧凑。这使得JWT是在HTML和HTTP环境中传递的不错的选择。
在安全方面,Simple Web Tokens (SWT)只能被对称签名通过使用HMAC算法由共享秘钥进行。但是,JWT和SAML Token可以使用X.509证书形式的公私钥对进行签名。与签名JSON的简单性相比,使用XML数字签名对XML进行签名而不引入模糊的安全漏洞是非常困难的。
JSON解析器在大多数编程语言中都很常见,因为它们直接映射到对象。相反,XML没有自然的文档和对象映射。与SAML相比,这使JWT更加容易使用。
关于用法,JWT是在Internet规模上使用的。这强调了在多个平台(尤其是移动平台)上对JWT进行客户端处理的简便性。
JWT 使用注意项:
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。同时也不便于查询实时在线用户。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明文传输,要使用 HTTPS 协议传输。
(7)客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。存储在Cookie中,就可以自动发送,但是不会跨域。为了支持跨域一般将它放入HTTP请求的Header Authorization字段中或者放置于POST请求的数据主体中。