Skip to main content
POST

概览

Ayrshare 会使用你的签名密钥作为 key,对每一次 webhook 投递的 payload 计算 HMAC-SHA256 签名,以便你的接收方能够确认该投递确实来自 Ayrshare。有关验证过程,请参见 Webhook 安全性 轮换你的签名密钥可以让你按固定周期替换它,或在你怀疑密钥已泄露时立即替换。为了让轮换过程安全,每次轮换后 Ayrshare 都会打开一个24 小时的宽限期,在此期间投递会同时用你的旧密钥和新密钥进行签名。这样你可以按自己的节奏更新接收方,而不会丢弃或拒绝任何一次投递 —— 这与 Stripe 和 GitHub 采用的模式一致。
签名密钥是按 profile 统一的:每个 User Profile (UID) 只有一个签名密钥, 它会对该 profile 已注册的每一个 webhook action 进行签名。不存在按 action 单独设置的签名密钥 —— 设置或轮换该密钥会同时改变该 profile 上所有 action 使用的密钥。

通过控制台轮换

你可以从开发者控制台的 Webhooks 页面 设置或轮换你的签名密钥。当该 profile 至少注册了一个 webhook 后,Signing Secret 面板会显示在你的 webhook 列表上方。
1

打开 Signing Secret 面板

前往 Webhooks 页面。如果尚未配置签名密钥,面板会显示 No signing secret configured 以及一个 Set Signing Secret 按钮。如果已经配置,则会显示 Signing secret configured 以及一个 Rotate 按钮。
2

设置或轮换

点击 Set Signing Secret(首次设置)或 Rotate(已有密钥)。弹窗会打开,其中预填并显示一个高强度、随机生成的密钥。你可以 Copy 复制它、Regenerate 重新生成一个新的,或切换 paste my own 使用你自己的值。
3

确认

请将密钥复制到安全的地方 —— 它只显示一次,之后无法再从 UI 中获取 —— 然后确认提交。会出现一个成功提示,面板也会随之更新。
4

更新你的接收方

在轮换(而非首次设置)时,面板会显示一个已激活的宽限期指示器,并且 Rotate 按钮在窗口关闭之前不可用。你有 24 小时将新密钥部署到你的接收方。

通过 API 轮换

只需一次调用即可轮换(或设置)签名密钥。该调用会创建一个新密钥,将该 profile 的密钥引用指向它,并在已有密钥存在时,将被替换掉的密钥记录为”旧密钥”,过期时间为 24 小时后。

Header 参数

Body 参数

string
必填
新的签名密钥值。可以是任何非空字符串。建议使用长度较长、熵较高的随机值(例如 32 个随机字节的 base64url 编码)。
响应中绝不会返回明文 secret,也绝不会被记录到日志。响应中携带的是面向客户端的 refId(UID 的哈希),而不是 UID 本身。Profile-Key header 是可选的,对多 profile 账户来说,它用于把此次轮换限定到单个 User Profile。 若缺失或为空的 secret,会返回一个已映射的错误(code: 101,“Missing/incorrect parameter”),HTTP 状态为 400,并且不会对你现有的密钥做任何改动。通过 API 进行首次设置(没有现有密钥)会创建密钥,不会记录旧密钥,也不会打开宽限期。

安全轮换流程

由于有 24 小时的宽限期,并不存在严格要求的操作顺序 —— 你的接收方在整个过程中都能正常工作。推荐的顺序如下:
1

轮换密钥

通过控制台或 API 进行轮换。Ayrshare 会立即开始同时使用你的旧密钥和新密钥对投递进行签名。
2

更新你的接收方

在 24 小时内,将新密钥部署到你的 webhook 接收方,以便使用新值进行验证。
3

等待窗口关闭

24 小时之后,Ayrshare 会自动清除旧密钥,只使用新密钥进行签名。你这一侧无需再做任何操作。
如果你在宽限期仍然打开时再次进行轮换,那么刚刚被替换掉的密钥会成为新的 “旧密钥”,并会开启一个全新的 24 小时窗口。同一时刻只保留一个旧密钥。

在宽限期内验证签名

在宽限期之外,已签名的投递会携带标准的 header(参见 Webhook 安全性):
在轮换后的 24 小时窗口内,新的 X-Authorization-Content-SHA256-V2 header 会同时列出两个签名,当前签名在前,以逗号分隔:
X-Authorization-Content-SHA256 保持不变:它始终只携带使用当前密钥计算出的 单个 HMAC,以保持向后兼容。双签名只会出现在新的 X-Authorization-Content-SHA256-V2 header 中。
X-Authorization-Content-SHA256-V2 中的每一个值都带有一个方案标签前缀。v1= 表示 HMAC-SHA256 签名,其计算方式与 X-Authorization-Content-SHA256 完全一致。只要一次投递被签名,-V2 header 就一定会出现 —— 它至少携带 v1=<current-sig> —— 因此你可以将其作为稳定的接收方契约来依赖。 在轮换期间(或宽限期之外)验证一次投递的方式:
1

计算 HMAC

使用你本地配置的签名密钥,对原始请求 body 计算 HMAC-SHA256。
2

与每一个列出的签名进行比对

读取 X-Authorization-Content-SHA256-V2,按逗号拆分,从每个值中去掉 v1= 前缀,只要你计算出的 HMAC 与任意一个列出的 v1= 签名相匹配,就把该投递视为可信。
只要有任意一个列出的签名匹配就接受 —— 这正是让轮换实现零停机的关键:仍配置旧密钥的接收方会匹配到 v1=<previous-sig>,而已更新为新密钥的接收方会匹配到 v1=<current-sig> —— 在整个窗口期内两者都能成功。

接收方验证示例

Node.js
务必对原始的请求 body 字节(与接收到时完全一致)计算 HMAC, 而不是对重新序列化后的 JSON 对象计算 —— 重新序列化可能改变空白字符 或 key 的顺序,从而导致验证失败。请使用常量时间比较(例如 crypto.timingSafeEqual)以避免时序攻击。
如果某次投递对应的当前密钥记录已丢失,该投递会以未签名方式(不带任何签名 header)送达,而不是失败。如果只是旧密钥记录已丢失,那么旧签名会被跳过,当前签名仍会出现在两个 header 中。