JWT
参考文献
概念
- JSON Web Token (JWT,RFC 7519),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。
使用场景
- 授权:这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够轻松地跨不同域使用。
- 信息交换:JSON Web 令牌是在各方之间安全传输信息的好方法。因为 JWT 可以进行签名(例如,使用公钥/私钥对),所以您可以确定发送者就是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改。
JWT
结构
-
在其紧凑形式中,
JSON Web Token
由用点 (.
) 分隔的三个部分组成,它们是:- Header 标头
- Payload 有效载荷
- Signature 签名
1
{header}.{payload}.{signature}
Header
标头
-
标头通常由两部分组成:令牌的类型(JWT)和所使用的签名算法(例如 HMAC SHA256 或 RSA)。
1
2
3
4{
"alg": "HS256",
"typ": "JWT"
} -
然后,对该 JSON 进行 Base64Url 编码以形成 JWT 的第一部分。
Payload
有效载荷
- 令牌的第二部分是有效负载,其中包含声明(
claims
).声明是关于实体(通常是用户)和额外数据的陈述。有三种类型的声明:注册声明(registered claims
)、公共声明(public claims
)和私有声明(private claims
)。
1 | { |
- 然后对有效负载进行 Base64Url 编码以形成 JSON Web 令牌的第二部分。
registered claims
- 注册声明: 这些是一组预定义的声明,不是强制性的,而是推荐的,以提供一组有用的、可互操作的声明。其中一些是:iss(issuer 发行者)、exp(expiration time 到期时间)、sub(subject 主题)、aud(受众 audience)等
- 请注意,声明名称只有三个字符长,因为 JWT 旨在紧凑。
public claims
- 公共声明:这些可以由使用 JWT 的人随意定义。但为了避免冲突,它们应该在 IANA JSON Web 令牌注册表中定义,或者定义为包含防冲突命名空间的 URI。
private claims
- 私人声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公开声明。
Signature
签名
- 要创建签名部分,必须获取编码的标头、编码的有效负载、秘密、标头中指定的算法,然后对其进行签名。
- 签名用于验证消息在传输过程中没有发生更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者是否是其所说的人.
1 | HMACSHA256( |
认证流程
用户认证的流程
- 用户使用账号(手机/邮箱/用户名)密码请求服务器
- 服务器验证用户账号是否和数据库匹配
- 服务器通过验证后发送给客户端一个 JWT Token
- 客户端存储 Token,并在每次请求时携带该 Token
- 服务端验证 Token 值,并根据 Token 合法性返回对应资源
客户端附带 JWT Token
的方式
-
用户在完成认证后会返回开发者一个 JWT Token,开发者需将此 Token 存储于客户端,然后将此 Token 发送给开发者受限的后端服务器进行验证。
-
建议使用 HTTP Header Authorization 的形式携带 Token
1
Authorization: "Bearer ID_TOKEN"
Bearer Token
- Bearer Token (RFC 6750) 用于授权访问资源,任何 Bearer 持有者都可以无差别地用它来访问相关的资源,而无需证明持有加密 key。一个 Bearer 代表授权范围、有效期,以及其他授权事项;一个 Bearer 在存储和传输过程中应当防止泄露,需实现 Transport Layer Security (TLS);一个 Bearer 有效期不能过长,过期后可用 Refresh Token 申请更新。
"alg" (Algorithm) Header Parameter Values for JWS
1 | +--------------+-------------------------------+--------------------+ |
JWT
问题
alg
字段的问题
-
使用 JWT 作为令牌,签名肯定是必要的。但是表示签名算法的 alg 字段,明文写在 HEADER 里。这是公认的标准设计问题,alg 字段本不该存在。
-
目前已知的攻击方式至少有两种:
- 将 alg 字段改为 “none” 攻击者按照格式构造一个JWT,并将 alg 字段设置为 none。如果验证方按照 JWT 的 alg 字段指定的算法验证 JWT,发现 alg 为 none,就直接通过验证了。
- 将非对称签名算法改为对称签名算法例如,将 alg=“RS256” 改为 alg=“HS256”。 攻击者截获一个 RS256 签名方式的 JWT,按照其格式构造并修改,设置 alg=“SHA256”,并使用公钥作为签名密钥签名。正常情况下,验证方按照 alg 字段指定的算法验证 JWT,发现 alg=“RS256”,使用公钥按照 RS256 算法验证;被使用次方式攻击时,发现 alg=“HS256”,则使用 HMAC-SHA256 算法,使用RSA的公钥作为签名密钥验证。公钥一般是公开的,所以这个构造是可能的。
对称密钥太短
- 对称密钥太短或者太有规律,就跟使用弱密码一样
明文
- PAYLOAD 是明文的,千万别把敏感信息写在 JWT 里。见过把用户的密码写在 JWT 里,被人拿到就泄露了; 也有把用户信息如手机号身份证号写在 JWT 里的,违反了大多数国家的法律法规。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 HoleLin's Blog!