背景与价值Webhook订阅需在引入前验证来源与控制权。挑战应答配合签名与窗口限制可有效防止伪造。统一规范来源白名单:仅接受受控域名的订阅请求。挑战应答:服务端生成挑战并要求客户端在窗口内签名返回。过期窗口:挑战在短窗口内有效,过期拒绝。核心实现挑战生成与校验function enc(s: string): Uint8Array { return new TextEncoder().encode(s) } async function importHmac(secret: ArrayBuffer): Promise<CryptoKey> { return crypto.subtle.importKey('raw', secret, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']) } async function hmac(key: CryptoKey, data: string): Promise<string> { const raw = await crypto.subtle.sign('HMAC', key, enc(data)) const u = new Uint8Array(raw) let s = '' for (let i=0;i<u.length;i++) s += String.fromCharCode(u[i]) return btoa(s).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'') } type Challenge = { id: string; exp: number; nonce: string } const store = new Map<string, Challenge>() function now(): number { return Date.now() } function genId(): string { return Math.random().toString(36).slice(2) } function issueChallenge(ttlMs = 30000): Challenge { const c: Challenge = { id: genId(), exp: now() + ttlMs, nonce: genId() } store.set(c.id, c) return c } async function verifyChallenge(id: string, sig: string, key: CryptoKey): Promise<boolean> { const c = store.get(id) if (!c) return false if (now() > c.exp) return false const expect = await hmac(key, c.nonce) return expect === sig } 落地建议为订阅请求下发挑战并要求在短窗口内返回HMAC签名,用以确认控制权。结合来源白名单与签名键治理,统一审计失败与异常请求。过期挑战统一清理并拒绝使用,避免重放与资源占用。验证清单挑战是否包含唯一ID与过期时间,签名是否匹配。是否按来源白名单与窗口限制实施门禁与审计。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
1.951886s