JWT

2 tools

Web 安全基础

Web 安全是保护 Web 应用程序和 API 免受未授权访问、数据泄露和攻击的实践。现代应用程序使用身份验证、授权和密码学来强制执行安全边界。

JSON Web Token(JWT)是现代 Web 开发中主流的无状态身份验证机制。理解 JWT 的工作原理——包括其结构、签名算法和漏洞——对于构建安全的 API 和应用程序至关重要。

JSON Web Tokens(JWT)

JWT 是一种紧凑的、URL 安全的方式,用于在两方之间表示声明。它由三个 Base64url 编码的部分组成,以点分隔。

JWT 的三个部分

Header

包含 token 元数据:签名算法(alg)和 token 类型(typ)。

已编码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
已解码
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload

包含声明:关于用户的陈述。Payload 数据未加密,只是被签名。

已编码
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzIwMDAwMH0
已解码
{
  "sub": "user_123",
  "role": "admin",
  "exp": 1717200000
}
Signature

对编码后的头部和 Payload 的密码签名。验证此签名可确保 token 未被篡改。

已编码
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
已解码
HMACSHA256(
  base64url(header) + "." +
  base64url(payload),
  secret
)

标准 JWT 声明

JWT 规范定义了标准声明名称以确保互操作性:

声明名称描述
issIssuer标识签发 token 的主体(如认证服务器 URL)
subSubject标识 token 的主题(如用户 ID)
audAudience标识 token 的预期接收者
expExpirationToken 不得在此 Unix 时间戳之后被接受
nbfNot BeforeToken 不得在此 Unix 时间戳之前被接受
iatIssued AtToken 签发时的 Unix 时间戳
jtiJWT IDToken 的唯一标识符,用于防止重放攻击

签名算法

签名算法在 JWT 头部中声明。为使用场景选择正确的算法对安全至关重要:

HS256 / HS384 / HS512对称(HMAC)

使用共享密钥进行签名和验证。

适用场景: 您控制所有参与方的内部服务。
RS256 / RS384 / RS512非对称(RSA)

使用私钥签名,使用公钥验证。私钥从不离开认证服务器。

适用场景: 微服务架构、第三方 token 验证、OAuth2 和 OpenID Connect。
ES256 / ES384 / ES512非对称(ECDSA)

类似 RSA,但密钥更小、签名更快。

适用场景: 性能重要的移动和 IoT 应用。
"alg": "none"无签名——危险

无签名。alg:none 的 token 无完整性保证,任何人都可以伪造。

适用场景: 永远不要在生产环境中使用。

认证流程

密码授权(直接)
  1. 1.用户向登录端点提交用户名和密码
  2. 2.服务器对照用户数据库验证凭据
  3. 3.服务器用用户声明和过期时间签署 JWT
  4. 4.客户端存储 JWT(localStorage、cookie 或内存)
  5. 5.客户端在后续请求的 Authorization: Bearer 头中发送 JWT
授权码 + PKCE(OAuth2)
  1. 1.客户端将用户重定向到带有代码挑战的授权服务器
  2. 2.用户进行身份验证并授权客户端应用
  3. 3.认证服务器以一次性授权码回调
  4. 4.客户端用代码 + 验证器换取访问令牌和刷新令牌
  5. 5.客户端使用访问令牌进行 API 调用;使用刷新令牌续期

常见 JWT 漏洞

正确实现时 JWT 是安全的。以下是最常见的实现错误:

算法混淆(alg:none)严重

某些库接受 alg:none 的 token。攻击者可以修改 payload 并将 alg 设置为 none 来伪造任意 JWT。

HS256/RS256 混淆严重

如果库应验证 RS256 但接受 HS256,攻击者可以用公钥作为 HMAC 密钥签署 token。

缺少过期验证

没有 exp 声明的 JWT,或不检查 exp 的代码,允许 token 被无限期使用。

Payload 中的敏感数据

JWT Payload 是 Base64 编码的,不是加密的。永远不要在 JWT 声明中存储密码或其他秘密。

弱密钥(HS256)

使用短或可预测密钥的 HMAC 签名 JWT 可以被离线暴力破解。

缺少签名验证

不验证签名就接受 JWT 完全信任 Payload。在信任任何声明前始终验证签名。

常见问题

JWT 是加密的吗?

标准 JWT(JWS)是已签名但未加密的。Payload 是 Base64url 编码的,可轻松解码。

JWT 应该有多长的有效期?

访问令牌应该是短期的:5–60 分钟很典型。使用刷新令牌获取新的访问令牌。

应该在浏览器中如何存储 JWT?

HttpOnly Cookie 是最安全的选项——JavaScript 无法访问,防止 XSS 窃取。

可以在过期前撤销 JWT 吗?

没有服务端状态就不行。解决方案:短过期时间、token 黑名单(Redis)。

JWT 和 Session Cookie 有什么区别?

Session Cookie 存储随机 Session ID;服务器查找 Session 数据。JWT 是自包含的——服务器无需数据库查询就能验证签名。

JWT 应该包含哪些声明?

最低要求:sub(用户 ID)、exp(过期时间)和 iat(签发时间)。保持 Payload 小巧。

RS256 比 HS256 更好吗?

RS256(非对称)对大多数生产系统更好,因为只有认证服务器需要私钥。

什么是 PKCE,为什么重要?

PKCE 是 OAuth2 授权码流程的扩展,防止授权码拦截攻击。公共客户端(SPA、移动应用)必须使用。