---

title: JWT令牌安全实践(短期有效、旋转与撤销)最佳实践

keywords:

  • JWT
  • HS256
  • RS256
  • 过期时间
  • jti
  • 撤销
  • Rotation
  • aud
  • iss
  • base64url

description: 统一令牌安全基线与可验证方案,包含短期有效策略、jti撤销与黑名单、密钥轮换与kid管理、aud/iss强校验与算法固定,附签发与验证示例。

categories:

  • 文章资讯
  • 技术教程

---

一、基线策略与参数

  • 有效期建议≤900秒;固定alg并校验kid;强校验aud/iss与时间偏差。
  • 令牌含jti并支持撤销;登录与敏感操作进行旋转与老令牌回收。

二、Base64URL与签名

import crypto from 'crypto'

function b64url(input: Buffer): string {
  return input.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
}

function b64urlJson(obj: any): string {
  return b64url(Buffer.from(JSON.stringify(obj)))
}

三、签发与验证(HS256示例)

type Key = { kid: string; key: Buffer }
type Claims = { sub: string; aud: string; iss: string; exp: number; nbf?: number; iat: number; jti: string; scope?: string[] }

function signHS256(header: any, payload: any, key: Buffer): string {
  const h = b64urlJson(header)
  const p = b64urlJson(payload)
  const data = `${h}.${p}`
  const mac = crypto.createHmac('sha256', key).update(data).digest()
  const s = b64url(mac)
  return `${data}.${s}`
}

function verifyHS256(token: string, key: Buffer, expectAlg: string): { ok: boolean; payload?: Claims } {
  const parts = token.split('.')
  if (parts.length !== 3) return { ok: false }
  const [h, p, s] = parts
  const head = JSON.parse(Buffer.from(h.replace(/-/g,'+').replace(/_/g,'/'), 'base64').toString('utf8'))
  if (head.alg !== expectAlg) return { ok: false }
  const data = `${h}.${p}`
  const mac = crypto.createHmac('sha256', key).update(data).digest()
  const expect = b64url(mac)
  if (expect !== s) return { ok: false }
  const payload = JSON.parse(Buffer.from(p.replace(/-/g,'+').replace(/_/g,'/'), 'base64').toString('utf8')) as Claims
  return { ok: true, payload }
}

四、签发与旋转

function nowSec(): number { return Math.floor(Date.now() / 1000) }

function randJti(): string { return crypto.randomBytes(16).toString('hex') }

function issueToken(key: Key, claims: Omit<Claims,'iat'|'jti'|'exp'>, ttlSec: number): string {
  const header = { alg: 'HS256', typ: 'JWT', kid: key.kid }
  const payload: Claims = { ...claims, iat: nowSec(), exp: nowSec() + ttlSec, jti: randJti() }
  return signHS256(header, payload, key.key)
}

function rotateToken(old: string, key: Key, ttlSec: number, expect: { aud: string; iss: string }): string | null {
  const v = verifyHS256(old, key.key, 'HS256')
  if (!v.ok || !v.payload) return null
  const pl = v.payload
  if (pl.aud !== expect.aud || pl.iss !== expect.iss) return null
  const fresh = issueToken(key, { sub: pl.sub, aud: pl.aud, iss: pl.iss, nbf: pl.nbf, scope: pl.scope }, ttlSec)
  return fresh
}

五、撤销与黑名单

class Revocation {
  store = new Set<string>()
  revoke(jti: string) { this.store.add(jti) }
  isRevoked(jti: string): boolean { return this.store.has(jti) }
}

function validateClaims(c: Claims, expect: { aud: string; iss: string; skewSec: number }, rev: Revocation): boolean {
  const now = nowSec()
  if (c.exp <= now) return false
  if (c.nbf && c.nbf - expect.skewSec > now) return false
  if (c.aud !== expect.aud || c.iss !== expect.iss) return false
  if (rev.isRevoked(c.jti)) return false
  return true
}

六、验收清单

  • exp≤900与固定alg=HS256;强校验kid/aud/iss与时间偏差。
  • jti并支持撤销;旋转后旧令牌加入黑名单;登录与敏感操作触发旋转。
  • 验证失败时拒绝并记录审计事件与jti关联。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部