← 返回博客

JWT Token 中的 Base64 编码解析

2026-04-18 · 5 分钟阅读

← 返回博客

JWT Token 中的 Base64 编码解析

· 5 分钟阅读

JWT 的三段结构

JWT(JSON Web Token,RFC 7519)是一种紧凑、自包含的方式,用于在各方之间以 JSON 对象的形式安全传输信息。一个 JWT 由三个 Base64URL 编码的字符串组成,以点(.)分隔:Header.Payload.Signature。每个部分都有明确的职责:头部描述令牌类型和签名算法,载荷包含声明(claims,即数据),签名用于验证令牌未被篡改。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

解码 JWT 头部(Header)

JWT 头部是一个 JSON 对象,经过 Base64URL 编码。典型的头部包含两个字段:alg(签名算法)和 typ(令牌类型,通常是 "JWT")。解码 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 会得到 {"alg":"HS256","typ":"JWT"}

# 解码 JWT 头部 / Decode JWT header
HEADER="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
# 添加填充并解码 / Add padding and decode
echo "${HEADER}==" | base64 --decode
# {"alg":"HS256","typ":"JWT"}

# Python 解码 / Python decode
import base64, json

def decode_jwt_header(token):
    header_b64 = token.split('.')[0]
    header_b64 += '=' * (4 - len(header_b64) % 4)
    return json.loads(base64.urlsafe_b64decode(header_b64))

解码 JWT 载荷(Payload)

JWT 载荷包含声明(claims)——关于实体(通常是用户)和附加数据的陈述。JWT 规范定义了一些标准声明:sub(主题,通常是用户 ID)、iss(颁发者)、exp(过期时间,Unix 时间戳)、iat(颁发时间)、aud(受众)。你也可以添加自定义声明(如用户角色、权限列表)。

// 解码完整 JWT(不验证签名)
// Decode full JWT (without signature verification)
function decodeJWT(token) {
  const [headerB64, payloadB64, signature] = token.split('.');

  function b64UrlDecode(s) {
    s = s.replace(/-/g, '+').replace(/_/g, '/');
    s += '=='.slice(0, (4 - s.length % 4) % 4);
    return JSON.parse(atob(s));
  }

  return {
    header: b64UrlDecode(headerB64),
    payload: b64UrlDecode(payloadB64),
    signature: signature
  };
}

const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0In0.xxx";
const decoded = decodeJWT(jwt);
console.log(decoded.payload.sub); // "1234"

JWT 载荷不是加密的

这是关于 JWT 最重要的安全提示:JWT 的头部和载荷只是 Base64URL 编码,任何人都可以解码并读取其内容。JWT 的安全性来自签名验证,而非数据保密。签名确保了数据没有被篡改,但不能防止数据被读取。

因此,永远不要在 JWT 载荷中存储敏感信息(如密码、信用卡号、社会保障号等)!如果你需要在 JWT 中保护敏感数据,应该使用 JWE(JSON Web Encryption)而非 JWS(JSON Web Signature,即普通的 JWT)。

验证 JWT 签名的正确方式

JWT 签名是对头部和载荷(Base64URL 编码形式)用指定算法(如 HMAC-SHA256)计算的结果,再进行 Base64URL 编码。验证签名意味着:用相同的密钥和算法重新计算签名,然后与 JWT 中的签名进行比较。如果匹配,则令牌是真实的且未被篡改。

# Python 验证 JWT(使用 PyJWT 库)
# Verify JWT in Python (using PyJWT library)
import jwt

SECRET_KEY = "your-256-bit-secret"

# 生成 JWT / Generate JWT
token = jwt.encode(
    {"sub": "user123", "role": "admin", "exp": 1735689600},
    SECRET_KEY,
    algorithm="HS256"
)

# 验证 JWT / Verify JWT
try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    print(f"Valid! User: {payload['sub']}")
except jwt.ExpiredSignatureError:
    print("Token has expired")
except jwt.InvalidTokenError:
    print("Invalid token")

常见的 JWT 安全错误

(1)将算法设为 "none":早期的 JWT 库接受 alg: "none"(无签名),攻击者可以伪造任意 JWT。始终在验证时明确指定允许的算法,并拒绝 alg: "none"。(2)将 RS256 的公钥当私钥攻击:当服务器支持 RS256 和 HS256 时,攻击者可能将 alg 改为 HS256,并用服务器的公钥作为 HMAC 密钥伪造 Token。始终在验证时强制指定预期算法。

(3)在载荷中存储敏感数据(前面已强调)。(4)使用弱密钥:HS256 的密钥应该足够长(至少 256 位),使用强随机数生成,避免使用简单的字符串如 "secret"。(5)不验证过期时间:始终验证 exp 声明,拒绝已过期的令牌。

调试和检查 JWT

调试 JWT 问题时,最常用的工具是 jwt.io(在线 JWT 解码和验证工具)。将 JWT 粘贴到 jwt.io,可以立即看到解码后的头部和载荷内容,以及(如果提供密钥)签名验证结果。我们的 Base64 工具也可以用于解码 JWT 的某个部分(记得先去掉点和其他段)。

在生产环境中,当遇到 JWT 相关错误时,常见的调试步骤是:先解码载荷查看 exp(过期时间)和 iss(颁发者)是否正确;检查 alg 字段与服务器期望的算法是否一致;确认时钟同步(JWT 过期检查依赖系统时钟,时钟偏差会导致问题)。

立即尝试在线工具,无需安装,免费使用。

打开工具 →

立即免费使用相关工具

免费使用 →