JWT
2 tools
Web 安全基础
Web 安全是保护 Web 应用程序和 API 免受未授权访问、数据泄露和攻击的实践。现代应用程序使用身份验证、授权和密码学来强制执行安全边界。
JSON Web Token(JWT)是现代 Web 开发中主流的无状态身份验证机制。理解 JWT 的工作原理——包括其结构、签名算法和漏洞——对于构建安全的 API 和应用程序至关重要。
JSON Web Tokens(JWT)
JWT 是一种紧凑的、URL 安全的方式,用于在两方之间表示声明。它由三个 Base64url 编码的部分组成,以点分隔。
JWT 的三个部分
包含 token 元数据:签名算法(alg)和 token 类型(typ)。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9{
"alg": "HS256",
"typ": "JWT"
}包含声明:关于用户的陈述。Payload 数据未加密,只是被签名。
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzIwMDAwMH0{
"sub": "user_123",
"role": "admin",
"exp": 1717200000
}对编码后的头部和 Payload 的密码签名。验证此签名可确保 token 未被篡改。
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHMACSHA256( base64url(header) + "." + base64url(payload), secret )
标准 JWT 声明
JWT 规范定义了标准声明名称以确保互操作性:
| 声明 | 名称 | 描述 |
|---|---|---|
| iss | Issuer | 标识签发 token 的主体(如认证服务器 URL) |
| sub | Subject | 标识 token 的主题(如用户 ID) |
| aud | Audience | 标识 token 的预期接收者 |
| exp | Expiration | Token 不得在此 Unix 时间戳之后被接受 |
| nbf | Not Before | Token 不得在此 Unix 时间戳之前被接受 |
| iat | Issued At | Token 签发时的 Unix 时间戳 |
| jti | JWT ID | Token 的唯一标识符,用于防止重放攻击 |
签名算法
签名算法在 JWT 头部中声明。为使用场景选择正确的算法对安全至关重要:
HS256 / HS384 / HS512对称(HMAC)使用共享密钥进行签名和验证。
RS256 / RS384 / RS512非对称(RSA)使用私钥签名,使用公钥验证。私钥从不离开认证服务器。
ES256 / ES384 / ES512非对称(ECDSA)类似 RSA,但密钥更小、签名更快。
"alg": "none"无签名——危险无签名。alg:none 的 token 无完整性保证,任何人都可以伪造。
认证流程
- 1.用户向登录端点提交用户名和密码
- 2.服务器对照用户数据库验证凭据
- 3.服务器用用户声明和过期时间签署 JWT
- 4.客户端存储 JWT(localStorage、cookie 或内存)
- 5.客户端在后续请求的 Authorization: Bearer 头中发送 JWT
- 1.客户端将用户重定向到带有代码挑战的授权服务器
- 2.用户进行身份验证并授权客户端应用
- 3.认证服务器以一次性授权码回调
- 4.客户端用代码 + 验证器换取访问令牌和刷新令牌
- 5.客户端使用访问令牌进行 API 调用;使用刷新令牌续期
常见 JWT 漏洞
正确实现时 JWT 是安全的。以下是最常见的实现错误:
某些库接受 alg:none 的 token。攻击者可以修改 payload 并将 alg 设置为 none 来伪造任意 JWT。
如果库应验证 RS256 但接受 HS256,攻击者可以用公钥作为 HMAC 密钥签署 token。
没有 exp 声明的 JWT,或不检查 exp 的代码,允许 token 被无限期使用。
JWT Payload 是 Base64 编码的,不是加密的。永远不要在 JWT 声明中存储密码或其他秘密。
使用短或可预测密钥的 HMAC 签名 JWT 可以被离线暴力破解。
不验证签名就接受 JWT 完全信任 Payload。在信任任何声明前始终验证签名。
常见问题
标准 JWT(JWS)是已签名但未加密的。Payload 是 Base64url 编码的,可轻松解码。
访问令牌应该是短期的:5–60 分钟很典型。使用刷新令牌获取新的访问令牌。
HttpOnly Cookie 是最安全的选项——JavaScript 无法访问,防止 XSS 窃取。
没有服务端状态就不行。解决方案:短过期时间、token 黑名单(Redis)。
Session Cookie 存储随机 Session ID;服务器查找 Session 数据。JWT 是自包含的——服务器无需数据库查询就能验证签名。
最低要求:sub(用户 ID)、exp(过期时间)和 iat(签发时间)。保持 Payload 小巧。
RS256(非对称)对大多数生产系统更好,因为只有认证服务器需要私钥。
PKCE 是 OAuth2 授权码流程的扩展,防止授权码拦截攻击。公共客户端(SPA、移动应用)必须使用。