// docs / baas security / clerk hardening
Clerk 安全清单:20 项
Clerk 为你的应用处理身份验证、会话和组织 — 这意味着配置错误的 Clerk 集成就是身份验证绕过、会话固定向量或组织泄漏路径。本清单是涵盖密钥、会话配置、webhook、组织、JWT 模板和持续监控的 20 项审计。AI 编码工具用合理默认值快速配置 Clerk;本列表捕获它们留下的项目。
有关身份验证层配置错误是 AI 工具弱点的背景,请参阅 AI 编码工具为何留下安全漏洞。有关 Auth0 上的并行清单,请参阅 Auth0 安全清单。
环境密钥和源允许列表
Clerk 为每个项目发行两种不同的密钥。混淆或泄漏它们是第一个失败模式。
- 在浏览器中使用可发布密钥 (生产中为
pk_live_*,开发中为pk_test_*);仅在服务器上使用秘密密钥 (sk_live_*/sk_test_*)。可发布密钥在NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY中是安全的;秘密密钥绝不能带有公共 env 前缀,绝不能出现在客户端组件中。 - 验证生产应用使用
pk_live_*而非pk_test_*。测试实例允许未验证的电子邮件地址和已禁用的 MFA — 将测试模式发布到生产是一种身份验证绕过。 - 在 Clerk 仪表板中配置允许的源。Settings → Domains → Allowed origins 必须准确列出你的生产域名。空或通配符源列表让攻击者能够创建与你的后端通信的伪造 Clerk 前端。
- 在任何离职或疑似泄漏时轮换秘密密钥。仪表板 → API Keys → Reset。旧密钥失效;在轮换前用新值重新部署服务端代码。
会话配置
会话过期和闲置超时是被盗会话变成 10 分钟事件还是 30 天事件的差别。
- 对处理敏感数据的 SaaS 应用,将会话闲置超时设置为 30 分钟或更少。仪表板 → Sessions → Inactivity timeout。银行级应用应使用 5-10 分钟;标准 SaaS 30-60 分钟;消费者应用 1-7 天。默认为 7 天。
- 在密码更改、电子邮件更改和 MFA 注册时启用会话撤销。仪表板 → Sessions → Revoke on。这些是用户发起的安全事件;其他设备上的现有会话应被终止。
- 在每条受保护路由上验证服务端会话,而不仅是在登录时。在 Next.js 中:服务器组件 / API 路由中的
const { userId } = await auth();从 cookie 读取 JWT 并验证它。绝不信任仅 cookie 的检查。 - 在会话 cookie 上设置
SameSite=Lax(默认) 或Strict。在 DevTools → Application → Cookies 中验证。SameSite=None是 CSRF 向量 — 除非你明确配置了跨域身份验证设置,否则绝不使用。
Webhook 验证
Clerk webhook 在用户生命周期事件 (创建、更新、删除、session.ended) 上触发。它们是你数据库的同步机制 — 而伪造的 webhook 是一种数据库写入原语。
- 对每个 webhook 验证 Svix 签名。Clerk webhook 由 Svix 签名。使用
new Webhook(secret).verify(body, headers)。验证失败时用401拒绝。 - 将 webhook 密钥存储在环境变量中,绝不在代码中。密钥在每次仪表板重新生成时轮换 — 你的部署必须从 env 读取它,而非常量。
- 每个处理程序都要幂等。Webhook 投递可能重复。在
webhook_events表中使用svix-id标头作为主键来去重。在同一事务中包装状态变更和幂等插入。 - 在
user.deleted上,24 小时内硬删除或匿名化 PII。GDPR / CCPA 要求这样做。审计删除路径:哪些表持有此用户的数据?在可能的地方使用 FK ON DELETE CASCADE。
组织和权限
如果你使用 Clerk Organizations,组织边界就是你的租户隔离。每个服务端查询都必须按它过滤。
- 在每条 API 路由上,从
auth()读取userId和orgId并按两者过滤数据库查询。WHERE org_id = $orgId AND user_id = $userId。绝不信任来自请求正文的org_id。 - 对特权操作使用 Clerk 角色检查,而非对用户对象进行布尔检查。
has({ role: 'org:admin' })从已验证的 JWT 读取角色。用户可以伪造过期客户端对象上的布尔值;他们无法伪造 JWT 声明。 - 用两个真实组织账户测试跨组织隔离。创建组织 A,填充数据,在另一浏览器中登录组织 B,尝试通过 API 读取组织 A 的数据。响应必须是
403或404。
JWT 模板和外部集成
JWT 模板将 Clerk 身份推送到 Supabase、Firebase 和其他下游服务。配置错误的模板过度共享声明或暴露你未打算暴露的数据。
- 对每个 JWT 模板,列出每个声明并确认其必要性。仪表板 → JWT Templates。向 Supabase 发送
email和phone的模板会向浏览器中读取 JWT 的任何人暴露 PII。 - 对用于客户端下游调用的 JWT 模板设置短过期时间。下游 API 请求 60 秒是标准。长寿命 JWT 会被盗并重放。
- 在接收端验证受众 (
aud) 声明。Supabase、Firebase 等应检查aud是否与预期服务标识符匹配。没有这个,为服务 A 发行的 JWT 可以认证到服务 B。
运营监控
身份验证是你拥有的最高信号日志源。监视它。
- 对每 IP / 每账户的登录失败激增告警。正常失败率的 50 倍是凭据填充攻击。Clerk 将这些事件发出到 webhook;将它们路由到你的 SIEM。
- 季度审查会话和实例设置漂移。随着 Clerk 更新,默认值会变;「旧配置」会随时间悄悄变错。将仪表板 JSON 导出与你上一个已知良好副本做差异比较。
后续步骤
Run a FixVibe scan against your production URL — it flags Clerk test keys in production and secret keys bundled into JavaScript. For the equivalent checklist on Auth0, see Auth0 security checklist. For the umbrella view across BaaS providers, read BaaS misconfiguration scanner.
