1. 什么是 JWT,它的结构是怎样的?
答:JWT 是 JSON Web Token 的简称,是一种开放标准(RFC 7519),用于在各方之间以 JSON 对象安全地传输信息。JWT 的设计目的是为了确保数据的完整性和来源可靠性。
JWT 的结构由三个部分组成:
- Header(头部):描述 JWT 的元信息,包括类型(通常为 JWT)和签名算法(如 HS256、RS256)。
- Payload(负载):存储具体的信息或声明(claims),比如用户 ID、过期时间等。
- Signature(签名):通过 Header 和 Payload 使用指定的算法生成,用于验证 JWT 的完整性。
JWT Token 实例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
2. JWT 如何保证数据的完整性?
答:JWT 使用签名(Signature)来保证数据的完整性。签名的生成方式是:
- 将 Header 和 Payload 分别进行 Base64Url 编码。
- 使用指定的签名算法(如 HMAC-SHA256 或 RSA)对编码后的字符串进行签名。
- 签名结果会附加到 JWT 的尾部,形成完整的 Token。
在验证过程中,服务器会重新计算签名并与收到的 JWT 签名进行对比。如果签名一致,则表明数据未被篡改。
注意:签名只能保证数据未被修改,但不能保护数据的机密性,Header 和 Payload 依然是可解码的。
3. JWT 的优缺点是什么?
优点:
- 无状态:JWT 不需要在服务器端保存用户会话数据,所有信息都存储在 Token 内,适合分布式系统。
- 易扩展:负载部分可以存储任意 JSON 格式的数据。
- 签名验证:通过签名可以验证数据的完整性和来源。
- 跨语言支持:JWT 标准被广泛支持,几乎所有语言都能使用。
缺点:
- 明文传输:JWT 的 Header 和 Payload 是 Base64Url 编码的,敏感信息容易暴露(除非使用加密)。
- Token 长度较长:与普通 Session ID 相比,JWT 的长度会占用更多带宽。
- 无法撤销:JWT 是无状态的,一旦签发,无法强制使其失效(除非使用黑名单等机制)。
4. JWT 是明文传输吗?如何保护数据的机密性?
答:是的,JWT 的 Header 和 Payload 是 Base64Url 编码的,这种编码方式是可解码的,因此它是明文的。如果 JWT 包含敏感信息(如用户密码等),需要额外加密。
保护数据机密性的方法:
- 使用 HTTPS:通过 HTTPS 协议传输 JWT,防止被窃听。
- 加密敏感数据:在存储到 Payload 中之前,对敏感数据进行加密。
- 使用 JWE:JWE(JSON Web Encryption)是 JWT 的扩展,它可以加密整个 Payload。
5. 如何验证 JWT 的合法性?
答:验证 JWT 的合法性包括以下步骤:
- 解码 JWT,获取 Header 和 Payload。
- 使用同样的算法(如 HS256)和密钥重新计算签名。
- 比较计算出的签名和 JWT 的签名部分,如果一致,则合法。
- 检查 Payload 中的声明(如 exp、iat)是否符合业务需求。
6. JWT 的有效期如何设置?
答:JWT 的有效期通过 Payload 中的声明字段设置:
- iat(Issued At):JWT 签发的时间。
- exp(Expiration Time):JWT 的过期时间,通常是一个时间戳。
- nbf(Not Before):JWT 开始生效的时间。
{
"iat": 1696563456,
"exp": 1696567056,
"nbf": 1696563456
}
当接收到 JWT 时,服务器会检查 exp 是否已过期,如果过期则拒绝请求。
7. JWT 的签名算法有哪些?
答:JWT 支持以下几种常用的签名算法:
- HMAC-SHA(对称算法):如 HS256、HS384、HS512。
使用单一密钥进行签名和验证,简单易用,但密钥需要妥善保管。 - RSA/ECDSA(非对称算法):如 RS256、ES256。
使用公钥和私钥,私钥签名,公钥验证,更加安全,适合分布式系统。
示例 Header:
{
"alg": "HS256",
"typ": "JWT"
}
8. 如何使 JWT 失效?
答:JWT 是无状态的,一旦签发就无法直接撤销。但可以通过以下方法实现失效:
- 设置短有效期:通过 exp 设置较短的过期时间,减少长时间有效的风险。
- 黑名单机制:将失效的 JWT 的 ID 或签发信息存储在服务器的黑名单中,每次验证时检查黑名单。
- 更新密钥:更换签名密钥,所有旧的 JWT 都会失效。
9. JWT 如何防止重放攻击?
答:防止重放攻击的措施:
- 使用 jti(JWT ID)字段:在每个 JWT 中添加唯一标识符,并在服务器端存储,防止重复使用。
- 设置短有效期:通过 exp 限制 Token 的生命周期。
- 结合 HTTPS:通过加密传输防止 Token 被窃取。
10. JWT 和 Session 的区别是什么?
对比点 | JWT | Session |
---|---|---|
存储位置 | 客户端(Token 存储在前端) | 服务器(会话信息存储在服务端) |
状态 | 无状态 | 有状态 |
扩展性 | 更适合分布式系统,易扩展 | 单点系统较方便,多节点需要共享会话 |
安全性 | 签名保证数据完整性,但内容是明文 | 数据保存在服务器,默认更安全 |
失效机制 | 需要通过黑名单或更新密钥实现 | 服务端直接销毁会话 |
11. JWT 是否适合大规模分布式系统?为什么?
答:JWT 非常适合大规模分布式系统,原因如下:
- 无状态性:JWT 不依赖服务端存储会话信息,完全由客户端携带,适合多节点系统,不需要共享会话。
- 跨语言支持:JWT 是标准协议,不依赖特定语言或框架,便于在多语言、多服务间通信。
- 灵活性:JWT 的 Payload 可以携带多种信息(如权限、角色等),方便系统扩展。
注意:在大规模系统中,需要使用以下策略避免 JWT 带来的问题:
- Token 短生命周期:减少长期有效的 Token 风险。
- 刷新机制:提供 Refresh Token 来重新生成短期有效的 Access Token。
- 签名密钥管理:使用非对称加密算法(如 RSA),在多个服务之间共享公钥。
12. 如何实现 JWT 的 Token 刷新机制?
答:实现 Token 刷新通常需要引入两种 Token:
- Access Token:短生命周期(如 15 分钟),用于访问受保护的资源。
- Refresh Token:生命周期较长(如 7 天),用于生成新的 Access Token。
实现流程:
- 客户端请求资源时携带 Access Token。
- 如果 Access Token 过期,使用 Refresh Token 请求服务器,服务器验证后生成新的 Access Token。
- 如果 Refresh Token 也过期,用户需要重新登录。
注意:Refresh Token 需要在服务端存储(如数据库、Redis)或使用更加安全的签名算法保护。
13. 如何设计安全的 JWT 签发和验证流程?
答:设计安全的 JWT 签发和验证流程需要遵循以下原则:
- 使用 HTTPS:确保传输过程的安全性,防止中间人攻击。
- 选择合适的签名算法:
如果是单机服务:可以使用对称算法(如 HS256)。
如果是分布式服务:推荐使用非对称算法(如 RS256),签发时使用私钥,验证时使用公钥。 - 设置短生命周期:exp 字段设置较短的有效期。
- 不在 JWT 中存储敏感信息:如密码、银行卡号等。
- 验证关键字段:如 iss(签发者)、aud(接收方)和 iat(签发时间)。
- 引入黑名单机制:用于处理需要立即失效的 Token。
14. JWT 是否可以用于授权?如何实现?
答:是的,JWT 不仅可以用于认证,还可以用于授权。
- 在 Payload 中添加用户权限相关字段,例如:
{
"sub": "1234567890",
"role": "admin",
"permissions": ["read", "write", "delete"]
}
- 服务端在验证 JWT 后,根据 role 或 permissions 字段决定用户是否有权限执行某些操作。
- 客户端可以根据 Payload 内容调整 UI 显示,比如隐藏没有权限的按钮。
15. JWT 和 OAuth 的关系是什么?
答:JWT 和 OAuth 是两种不同的技术,但可以结合使用:
- OAuth 是一个授权框架,用于授权第三方应用访问资源。
- JWT 是一种令牌格式,常用于 OAuth 的 Access Token。
结合点:
- 在 OAuth 2.0 中,JWT 常被用作 Access Token 的格式。
- OAuth 负责授权逻辑,JWT 负责在授权完成后传递认证和授权信息。
用户登录成功后,OAuth 授权服务器生成一个 JWT,客户端使用此 JWT 访问资源服务器。
16. 如何防止 JWT 被盗用?
答:防止 JWT 被盗用需要多种安全策略:
- 使用 HTTPS:加密传输,防止网络窃听。
- Token 短生命周期:即使 Token 被盗,生命周期结束后也会失效。
- 绑定 IP 或设备信息:在 Payload 中存储 IP 地址或设备信息,验证时确保与当前请求一致。
- 双 Token 机制:使用短期 Access Token 和长期 Refresh Token,Access Token 被盗后风险可控。
- 签名密钥保护:密钥泄露会导致伪造 Token,需要使用安全的密钥管理工具(如 AWS KMS)。
17. 为什么 JWT 不适合存储大量数据?
答:JWT 的主要设计目标是传递少量的认证或授权信息,而不是用来存储大量数据。
原因:
- 带宽浪费:JWT 每次请求都需要携带完整的 Token,数据量过大会浪费带宽。
- 性能问题:解码和验证较大的 Token 会增加服务器负担。
- 安全性问题:存储大量数据可能增加敏感信息泄露的风险。
建议:
- 在 JWT 中只存储必要的声明(如用户 ID 和权限)。
- 使用后端数据库或缓存(如 Redis)存储额外的用户数据。
18. JWT 如何处理多用户多设备登录场景?
答:在多用户、多设备场景中,需要处理以下问题:
- 区分设备:在 JWT 的 Payload 中添加设备标识(如设备 ID 或 User-Agent)。
{
"sub": "1234567890",
"device": "device123"
}
- 多设备同时登录:
服务端允许同一用户在多个设备上生成独立的 JWT。
在数据库中为每个设备维护独立的 Token 信息,便于管理。 - 单设备登录:
新设备登录时,注销其他设备的 Token。
通过维护 Token 的状态表(如 Redis),使之前的 Token 无效。
19. JWT 的 Payload 是否可以被篡改?
答:JWT 的 Payload 是可以被修改的,但篡改后的 Token 无法通过签名验证。
- JWT 的签名(Signature)是根据 Header 和 Payload 生成的,任何篡改都会导致签名验证失败。
- 服务器在验证时会重新生成签名,与 JWT 的签名部分对比,发现不一致就拒绝请求。
20. 如何使用 JWT 实现用户注销功能?
答:由于 JWT 是无状态的,无法直接从服务器“注销”用户,但可以通过以下方法实现:
- 短生命周期:
将 JWT 的有效期设置很短,用户下次请求需要重新获取 Token。 - 黑名单机制:
在服务端维护一个黑名单,将需要注销的 JWT 的 jti 存入黑名单。
每次验证 Token 时,检查黑名单,如果存在则拒绝请求。 - Token 刷新策略:
当用户选择注销时,将当前 Refresh Token 标记为失效,无法再生成新的 Access Token。
评论区