背景与价值 HTTP消息签名以标准化组件列表构建签名基串并下发签名头,资源端可验证消息完整性与来源可信度,降低重放与篡改风险。 统一规范 - 组件列表:明确签名包含的头、方法与路径(如 `@method`、`@path`、`content-digest`)。 - 算法限定:采用 `ES256`;`keyid` 标识公钥并支持轮换。 - 时间窗口:可选 `created/expires` 提供短期有效窗口。 核心实现 组件与基串构建 ```ts type Req = { method: string; path: string; headers: Record } type Component = '@method' | '@path' | string // header name in lower-case function h(req: Req, k: string): string { return (req.headers[k] || '').trim() } function buildBase(req: Req, components: Component[]): string { const lines: string[] = [] for (const c of components) { if (c === '@method') lines.push(`"@method": ${req.method.toLowerCase()}`) else if (c === '@path') lines.push(`"@path": ${req.path}`) else lines.push(`"${c}": ${h(req, c)}`) } return lines.join('\n') } function buildSignatureInput(components: Component[], params: { alg: 'ES256'; keyid: string; created?: number; expires?: number }): string { const items = components.map(c => c).join(' ') const p: string[] = [`alg=${params.alg}`, `keyid="${params.keyid}"`] if (params.created) p.push(`created=${params.created}`) if (params.expires) p.push(`expires=${params.expires}`) return `(${items});` + p.join('; ') } ``` 签名与验证(ES256) ```ts function enc(s: string): Uint8Array { return new TextEncoder().encode(s) } function b64u(b: ArrayBuffer): string { const u = new Uint8Array(b); let s=''; for (let i=0;i { return crypto.subtle.importKey('pkcs8', pkcs8, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']) } async function importPublicKey(spki: ArrayBuffer): Promise { return crypto.subtle.importKey('spki', spki, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']) } async function signBase(base: string, key: CryptoKey): Promise { const raw = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, key, enc(base)); return b64u(raw) } async function verifyBase(base: string, sigB64u: string, key: CryptoKey): Promise { return crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, key, buf(sigB64u), enc(base)) } ``` 窗口校验 ```ts function timeNow(): number { return Math.floor(Date.now()/1000) } function within(created?: number, expires?: number, leeway = 300): boolean { const n = timeNow(); if (created && created - leeway > n) return false; if (expires && expires + leeway < n) return false; return true } ``` 落地建议 - 在请求包含 `Signature-Input` 与 `Signature`;组件与参数明确,启用时间窗口。 - 资源端按组件构建基串并验签,校验 `created/expires` 与 `keyid` 轮换策略。 验证清单 - 组件列表是否正确;签名算法与基串校验是否通过;时间窗口是否有效。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部