一、基线与风险风险:伪造请求、密钥泄露重放、时钟漂移放大、缓存链路污染。基线:固定算法与头字段、时间戳与窗口校验、nonce唯一性与回收、体内容规范化。

二、签名生成import crypto from 'crypto'

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

function signWebhook(body: string, tsSec: number, nonce: string, secret: Buffer): string {

const data = `${tsSec}.${nonce}.${body}`

const mac = crypto.createHmac('sha256', secret).update(data).digest()

return b64url(mac)

}

三、服务端校验与重放窗口type Req = { headers: Record<string, string | undefined>; rawBody: string }

type Res = { status: (n: number) => Res; end: (b?: string) => void }

class NonceStore {

keep = new Set<string>()

add(n: string) { this.keep.add(n) }

has(n: string): boolean { return this.keep.has(n) }

del(n: string) { this.keep.delete(n) }

}

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

function verifyWebhook(req: Req, res: Res, secret: Buffer, windowSec: number, nonces: NonceStore): boolean {

const sig = req.headers['x-signature'] || ''

const ts = Number(req.headers['x-timestamp'] || '0')

const nonce = req.headers['x-nonce'] || ''

if (!Number.isFinite(ts)) return false

if (Math.abs(nowSec() - ts) > windowSec) return false

if (nonces.has(nonce)) return false

const expect = signWebhook(req.rawBody, ts, nonce, secret)

if (expect !== sig) return false

nonces.add(nonce)

return true

}

四、整合与验收function guardWebhook(req: Req, res: Res, secret: Buffer, store: NonceStore) {

const ok = verifyWebhook(req, res, secret, 300, store)

if (!ok) return res.status(401).end('invalid_signature')

}

头字段:`X-Signature/X-Timestamp/X-Nonce`;窗口≤`300`;`nonce`一次性。签名覆盖顺序为`ts.nonce.body`,体需为规范化字符串;失败时拒绝且记录审计。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部