一、基线策略与参数有效期建议≤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`关联。

发表评论 取消回复