---
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关联。

发表评论 取消回复