Simmetric Chat 的安全层:API key、签名 webhook 与 DLP
Simmetric Chat 如何认证每个请求、用 HMAC-SHA256 哈希 API key、签名 webhook 和 Web Push,并用 DLP 过滤器脱敏个人信息。
安全是一套栈,不是一个开关
一个保管你公司文档的聊天平台必须通过层层机制赢得信任:请求如何认证、程序化访问如何签发与保存、后台集成如何证明自身合法性,以及敏感内容流经 prompt 和回答时会发生什么。Simmetric Chat 用具名机制应对每一个方面,v0.22 关闭了一些最微妙的缺口--timing-safe 的密钥比较、抗枚举的登录,以及如今还覆盖结构化欧洲标识符的 DLP 引擎。本文从大门向内走遍这套栈。
请求认证的三种方式
/api 下的每个端点都落在三种凭证制度之一:
- JWT Bearer(主要方式)。 人类用户通过登录或注册端点认证,获得签名 JWT。每个 token 携带
jticlaim,对照撤销列表校验(可选依托 Redis),因此登出或管理员撤销立即生效,而不是等到过期。无效或过期的 token 收到干净的401;中间件在每个请求上解析用户及其角色与权限。 - API key(`X-Api-Key`)。 程序化访问--widget 的服务账户表面和用户通过 API-key 端点创建的密钥--使用带前缀的密钥,对照 HMAC digest 校验,详见下文。
- Collector 共享密钥。 摄取 collector 的服务间调用携带
X-Collector-Secret,以恒定时间比较并带长度守卫。这是服务器上最后残留明文密钥比较的地方,v0.22 把它关上了:archive 导入回调现在使用与其他所有密钥屏障相同的crypto.timingSafeEqual纪律。
认证之上是 RBAC 守卫,另有文章讨论--权限检查、admin 屏障,以及 workspace 和项目访问上的 IDOR 防护。认证回答「你是谁」;RBAC 回答「你能碰什么」。
API key:HMAC-SHA256,静态加密
API key 是 bearer 凭证,因此服务器如何保存它与如何校验它同样重要。Simmetric Chat 签发带可识别 sk- 前缀的密钥--对大多数开发者已在使用的工具生态来说很熟悉--并且从不保存密钥本身。静态时,每个密钥只以 HMAC-SHA256 digest 的形式存在,在专用服务端密钥 API_KEY_HMAC_SECRET 下计算:
sk-abc123…(签发一次,只向调用方展示一次)
│ HMAC-SHA256(API_KEY_HMAC_SECRET, 密钥)
▼
key_hash 保存在 api_keys 中 - 密钥本身不可恢复该设计有两个刻意为之的属性:
- 解耦轮换。
API_KEY_HMAC_SECRET独立于JWT_SECRET和ENCRYPTION_KEY。轮换会话签名密钥不会使 API key 失效,轮换静态加密密钥不会破坏密钥校验。每个密钥只承担一项职责。 - 恒定时间校验。 校验是一次带密钥的 HMAC digest 查找--O(1),没有对候选扫描的
take限制。这正是 API key 认证在多实例部署中足够便宜、能出现在每个请求上的原因。
用户通过 API-key 端点管理自己的密钥:按需创建、按需列出、按需撤销。撤销移除了重建有效凭证的能力;digest 不再匹配任何东西。
签名 webhook 与 Web Push
出站集成必须与入站一样可验证。
Webhook 用 HMAC-SHA256 签名。服务器用 webhook 密钥对 payload 计算签名,你的接收服务在信任事件体之前重新计算 digest。接收端点永远不应信任自称是 Simmetric Chat 的调用方--它可以用自己的密钥副本逐字节证明这一点。测试事件端点让你演练接收方而无需在平台上产生真实活动。
Web Push 使用 VAPID 协议发送浏览器通知。服务器持有一对 VAPID 密钥;公钥通过系统端点暴露给已认证客户端,订阅通过显式的 subscribe/unsubscribe 端点管理,管理员可以发送测试推送来端到端验证管线。两个渠道在 Community 层级始终启用--签名和推送是平台的基础行为,不是 enterprise 功能。
边界上的速率限制
速率限制按表面分层,在受限路由上发出惯常的 RateLimit-* 头:
- 全局 API 限制器--生产环境所有路由每 IP 每分钟 200 次请求
- 认证限制器--认证写端点每分钟 10 次请求,最严的屏障,因为凭证端点是滥用的首要目标
- Widget lead 限制器--lead 捕获每小时 3 次请求,因为公开表单正是自动化滥用集中之处
- Probe 限制器--连通性 probe 端点每分钟 10 次请求,因此设置向导的测试无法被武器化
当 REDIS_URL 配置时,计数器活在共享 Redis 存储中,使限制在每个实例上含义一致;否则每个实例维护自己的存储。带 widget 头的请求跳过全局限制器--widget 流量已由 widget 服务的按 key 限制器在上游节流--而且没有专门的聊天限制器,因为 agent 在内部强制每用户并发、token 预算和墙钟超时。
DLP:外泄前的脱敏
Simmetric Chat 的数据防泄漏是一个过滤器插件,既扫描入站 prompt 也扫描出站回答--包括流式的逐 token 渐进刷新--并在内容离开你的网络之前对匹配项脱敏。扫描器识别 10 类内置 PII pattern:
- 电子邮件地址
- 信用卡号
- API key 和私钥
- 加上结构化欧洲标识符:意大利 Partita IVA、codice fiscale 和 IBAN,在 v0.22 加入并幂等植入
Pattern 配置基于数据库并由管理员管理:按行启用或禁用任何 pattern,添加最多 50 个自定义 pattern,支持实时编译校验和测试预览,并查看可按来源(聊天或 widget)过滤的 DLP 匹配历史面板。内置正则被冻结--你可以禁用内置 pattern 但不能改写它--而自定义 pattern 承载你的定义。能读取已配置 pattern 的扫描通过短 TTL 缓存使用它们,数据库不可达时回落到内置集合,因此数据库中断永远不会停用脱敏。
两个治理细节补全画面。DLP_BYPASS_ROLES 设置允许管理员豁免特定角色免受扫描,每次 bypass 都会产生一条审计事件,记录谁 bypass 了以及在哪个表面--永远不记录被扫描的内容。管理员还可以通过一次对话用单一开关揭示或重新隐藏匹配文本,可见性限于会话且默认隐藏,因此脱敏对授权复核仍然可逆,但不会静默进行。
v0.22 中最微妙的加固
小改动重要,因为它们关闭攻击者真正探测的通道:
- 处处 timing-safe 比较。 每一处残留的明文密钥比较--collector 密钥屏障、archive 导入回调、widget 的 cache-bust key 检查--现在都使用
crypto.timingSafeEqual并带长度守卫,在期望密钥未设置时 fail-closed。 - 抗枚举登录。 当用户名不存在时,登录在响应前仍执行一次假哈希比较,因此响应时间不再区分存在与不存在的用户。无效请求体返回结构化的
400,而不是会让 Zod 内部细节泄露的401。 - 大声失败的错配。 API key 校验上的服务端 HMAC 错配返回
500,这是刻意的--错误配置的密钥绝不能伪装成认证失败。 - 结构化校验。 请求体用共享 Zod schema 通过
safeParse校验;每个错误都是带逐字段细节的统一信封,因此客户端以可预测的方式失败。
整个 API 表面--端点表、SSE 事件框架和逐路由的认证要求--记录在 API 参考中,服务器还内置了实时 Swagger 界面。
