<!-- Source: https://docs.infraio.xyz/zh-CN/security/api-keys -->
<!-- Last updated: 2026-10-04 -->

# API 密钥

三种凭据，三种威胁模型。

## `pk_` — Publishable

- 设计上就是要发到浏览器里的。作为 `X-Client-ID` 标头随每个已签
  名的 B2B 请求发送，也会内嵌在 SDK bundle 中用于客户端发起结账。
- 可以标识你的账户；但不能创建会话、读取其他商户的数据，或触发
  任何破坏性操作。
- 泄露一个 publishable key 是**低严重性**事件。

## `sk_` — Secret（HMAC 签名密钥）

- 所有 B2B API 调用的 HMAC-SHA256 签名密钥 — 见
  [身份验证](https://docs.infraio.xyz/zh-CN/api-reference/authentication)。
- 永远不会在网络上传输。传输的只是它针对每次请求派生出的签名。
  所以你只需要担心*存储*层的泄露（环境变量、git、日志），不用担
  心传输层。
- 仅限服务端。绝不应该出现在浏览器 bundle、公开仓库、截图或聊天
  消息里。
- 泄露一个 secret 是**高严重性**事件。

## `whsec_` — Webhook 签名密钥

- 用于验证我们向你服务器**入站**投递的 webhook 签名。见
  [签名验证](https://docs.infraio.xyz/zh-CN/webhooks/signature-verification)。
- 每个 webhook 端点各自独立 — 如果你注册了 3 个端点，就有 3 个不
  同的 `whsec_` 密钥。环境编码在前缀里：`whsec_live_…` /
  `whsec_test_…`。
- 仅限服务端。和 `sk_` 一样，永远不会在网络上传输 — 只用于在本地
  验证 HMAC。
- **轮换有 24 小时宽限窗口。** 点击 Rotate 后，旧密钥会在新密钥生
  效的同时继续被接受 24 小时（投递会同时携带 `X-Signature` 和
  `X-Signature-Prev`），这样你就能在不阻塞流量的情况下重新部署验
  证逻辑。
- **重新展示已有密钥**功能是有的，需要重新完成 2FA 验证，并会记
  录到审计日志 — 用于密钥丢失、又不能接受轮换的情况。仪表板默认
  的姿态是"轮换，而不是展示"。
- webhook secret 一旦泄露，攻击者就能向你的 URL 伪造事件。严重程
  度**中到高**，取决于你有多信任事件负载的内容。

## Scope

Secret key 是带 scope 的。仪表板允许你用以下 scope 组合之一铸造
密钥：

| Scope | 可以做什么 | 用于 |
| --- | --- | --- |
| `read` | 列出 / 读取订单、会话、退款、余额 | 只读集成（分析、BI） |
| `write_order` | 全部 `read` 权限 + 创建会话、创建订单、取消订单 | 商店后端 |
| `write_refund` | 全部 `read` 权限 + 创建退款、把退款标记为已执行 | 客服工具 |
| `webhook_manage` | 全部 `read` 权限 + 管理 webhook 端点 | DevOps 工具 |

默认铸造的"full access"密钥拥有全部四种 scope。按用途分别铸造密
钥仍然是好习惯,因为它能记录意图,但在把 scope 当作安全边界之前，请先阅读下面的提醒。

> **Warning:**
>
> **scope 目前尚未强制执行。** 一个泄露的 `sk_`，不论它挂着*什么*
> scope，都能调用你商户名下*任意* `/b2b/v1/*` 端点。一个 `read`
> 密钥并不会被阻止创建退款。所以收窄 scope 目前**并不能**
> 限制泄露造成的损害：做安全规划时，请把每个 secret key 都当作
> full access 来对待，并依靠下文的快速轮换和吊销来控制泄露。

## 轮换

1. **生成新密钥。** 仪表板 → **Developers → API keys** →
   **+ Add key**。选择 scope。仪表板**仅展示一次**密钥 — 请立刻
   保存。
2. **把环境变量**更新为新值，覆盖所有环境。然后部署。
3. **验证流量。** 仪表板会实时展示每个密钥的请求数。等旧密钥的请
   求数降到零。
4. **吊销旧密钥。** 在同一个页面 → kebab 菜单 → **Revoke**。

> **Warning:**
>
> **目前没有自动重叠窗口** — 一旦你吊销某个密钥，任何用它签名的在
> 途请求都会收到 `401`。请相应地规划轮换流程：先部署新密钥，排空
> 旧密钥的流量，再吊销。

## 紧急吊销

如果密钥已经泄露（出现在 git 历史、公开的 bundle、被记录的堆栈跟
踪，或合作伙伴的渗透测试报告中）— 立刻吊销，哪怕会导致一些请求失
败。让失败明显地发生，也好过让攻击者手握一个有效凭据。

步骤：

1. **仪表板 → Developers → API keys → [key] → Revoke now。** 立
   即生效，没有宽限期。
2. 铸造一个替代密钥并部署。
3. 审计近期活动 — 仪表板会展示每个密钥最近 30 天的请求记录，包括
   IP 和命中的端点。

如果你怀疑泄露范围不止一个密钥，请联系 contact@lartech.xyz 来：

- 获取你商户账户的完整审计日志导出
- 批量轮换 webhook secret
- 在你调查期间，可选择冻结账户

## 存储最佳实践

- **只用环境变量。** 永远不要把 secret 提交进 git，哪怕是在写着
  "REPLACE ME"的 `.env.example` 里。
- **按环境区分密钥。** dev / staging / prod 使用不同的
  `sk_test_…` 和 `sk_live_…`，从你的密钥管理系统中获取（AWS
  Secrets Manager、Vault、Doppler……）。
- **限制环境变量的访问权限。** 在 Kubernetes 中以 `Secret` 挂
  载，而不是 `ConfigMap`。在 Vercel / Netlify 中使用按环境变量的
  scope，而不是项目级全局变量。
- **不要记录带 body 的请求日志。** 即便是在调试时也不要 —
  `X-Signature` 里的 HMAC 签名是一次性的，但你的业务负载可能包含
  PII。

## 目前还不支持什么

- ❌ 针对 secret key 的 **IP 白名单**。
- ❌ **OAuth 风格的按用户 scope token。** 目前的密钥模型是按商户
  的，不是按用户的。
- ❌ **自动密钥轮换**（例如平台强制每周轮换一次）。轮换需要手动完成。

## 下一步

- [身份验证](https://docs.infraio.xyz/zh-CN/api-reference/authentication) — B2B 调用的精
  确签名算法。
- [Webhooks → 签名验证](https://docs.infraio.xyz/zh-CN/webhooks/signature-verification) —
  `whsec_` 在入站事件上如何使用。
