7.0 KiB
JWT
JSON Web Token是一个开源标准,定义了一种紧凑且自自包含的方式,用于在各方之间安全的传输信息,这些信息以JSON对象的形式呈现。传输的信息是被数字签名的,故而信息可以被验证并信任。
JWT可以通过密钥(使用hmac算法)或public/private key pair(使用RSA/ECDSA算法)来进行签名。
即使JWT可以通过加密在传递过程中提供安全性,但是本文会集中在signed tokens:
signed tokens: signed tokens可以验证token中包含声明的完整性encrypted tokens: 加密则是将token中的claims内容向第三方隐藏
JWT应用场景
如下是JWT的常用场景:
- Authorization:这是JWT的最通用场景。一旦用户登录,后续的请求都会包含JWT,允许用户访问该JWT被允许的路由、服务、资源。
单点登录特性普遍使用JWT,其带来开销较小,并且能够轻松的跨domains使用
- Information Exchange:JWT能够安全的在各方传递信息。由于JWT可以被签名,例如在使用public/private key时,可以确保发送方身份的可靠性。
- 并且,由于签名是通过header和payload进行计算的,还可以用于验证token内容是否被修改
JSON Web Token结构
JWT的结构较为紧凑,由三个部分组成,三个部分之间通过.进行分隔:
- Header
- Payload
- Sinature
因此,JWT通常看起来如下:
xxxxx.yyyyy.zzzzz
Header
header通常由两部分组成,
- token的类型:JWT
- 使用的签名算法: HMAC/SHA256/RSA
示例如下所示:
{
"alg": "HS256",
"typ": "JWT"
}
对于JWT的第一部分而言,json形式的内容会被以Base64Url的形式进行编码。
Payload
token的第二部分是payload,包含了token中的claims:
claim:即对某个实体及其附加数据的描述(实体通常是用户)
claims通常存在三种类型:
- registered
- public
- private
registered claims
存在一系列预定义的claims,并非强制,但是推荐进行使用。
iss: issuer,签发者exp: expiration time,过期时间sub:subject,主体,例如用户唯一标识aud:audience,接收方/受众,指JWT的目标接收方,限制token的使用范围
Public claims
pubic claims可以被jwt的使用者任意定义。但是,为了避免冲突,public claims应该在IANA JSON Web Token Registry中被定义,或在命名中包含namespace从而避免冲突。
private claims
private claims也可以被自由定义,用于在各方之间共享信息。
private claims和public claims的区别如下:
- private claims可以被任意定义,只需要传递的双方协商一致即可
- public claims的命名需要遵守相应规范,应在
IANA JSON Web Token Registry中或以URI的形式定义
payload的示例如下所示:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
作为JWT的第二部分,上述内容也会通过Base64Url的形式进行编码。
Signature
为了创建jwt的第三部分,必须接收如下内容:
- encoded header
- encoded payload
- secret
- header中指定的算法
可以根据上述内容生成签名。
例如,如果使用HMAC SHA256算法进行签名,签名应当以如下方式进行创建:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
HMACSHA256是一种基于hash的消息认证码算法,需要提供secret和待散列的消息
signature会被用于验证token内容是否被修改,并且,在使用private key进行签名时,可以验证jwt的签发方身份。
putting together
最终的jwt会将上述三个部分通过.分隔符拼接在一起。
JSON Web Tokens工作方式
在认证过程中,当用户通过凭据成功登录后,系统将会返回一个jwt。返回的token本身就是凭据,需谨慎对待避免出现安全问题。
通常,不应该在jwt中存储敏感的会话数据。
不论何时,当用户想要访问受保护的route和resource时,user agent都应该发送JWT。通常,JWT被包含在Authorization header中,并使用Bearer schema。header的内容如下所示:
Authorization: Bearer <token>
在http header中发送jwt时,必须避免jwt大小过大。部分server不接受超过8KB的headers。如果需要在jwt中集成较多信息,需要使用替代方案,例如Auth0 Fine-Grained Authorization。
下图展示了JWT获取和通过JWT访问API、资源的流程
- 应用或client会向authorization server请求授权
- 当授权被授予后,authorization server将会向应用返回access token
- 应用将会使用token去访问受保护资源
需要注意,在使用signed tokens时,token中的所有内容都会暴露给用户和其他方,即使他们无法修改这些信息。即不应该在token中包含机密信息。
JWT的validation和verification
jwt的validation和verification针对的是JWT的不同方面:
- validation:jwt的格式是否正确
- verification:确保jwt真实且未修改
Validation
JWT validation会检查jwt的结构、格式、内容:
- 结构:确保jwt是被
.符号分隔的三个部分(header, payload, signature) - format:校验每个部分都是使用Base64URL进行编码的的,并且payload包含预期的claims
- content:校验payload中的claims是否正确,例如过期时间(exp)、issued_at(iat)、not before(nbf)等,确保token没有过期,并且没有在生效前使用
Verification
verification保证的是jwt的真实性和完整性
- Signature Verification:其为验证的主要环节,会通过jwt的header和payload部分来校验jwt的signature部分。该部分会通过header中指定的算法(例如RSA/ECDSA/HMAC)来完成。如果签名不符合预期,token可能被修改或来源非可信源。
- Issuer Verification:校验
issclaim指定的内容是否和预期相符 - Audience Check:确保
audclaim和预期相符