FixVibe

// docs / baas security / clerk hardening

Clerk 安全清单:20 项

Clerk 为你的应用处理身份验证、会话和组织 — 这意味着配置错误的 Clerk 集成就是身份验证绕过、会话固定向量或组织泄漏路径。本清单是涵盖密钥、会话配置、webhook、组织、JWT 模板和持续监控的 20 项审计。AI 编码工具用合理默认值快速配置 Clerk;本列表捕获它们留下的项目。

有关身份验证层配置错误是 AI 工具弱点的背景,请参阅 AI 编码工具为何留下安全漏洞。有关 Auth0 上的并行清单,请参阅 Auth0 安全清单

环境密钥和源允许列表

Clerk 为每个项目发行两种不同的密钥。混淆或泄漏它们是第一个失败模式。

  1. 在浏览器中使用可发布密钥 (生产中为 pk_live_*,开发中为 pk_test_*);仅在服务器上使用秘密密钥 (sk_live_* / sk_test_*)。可发布密钥在 NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY 中是安全的;秘密密钥绝不能带有公共 env 前缀,绝不能出现在客户端组件中。
  2. 验证生产应用使用 pk_live_* 而非 pk_test_*测试实例允许未验证的电子邮件地址和已禁用的 MFA — 将测试模式发布到生产是一种身份验证绕过。
  3. 在 Clerk 仪表板中配置允许的源。Settings → Domains → Allowed origins 必须准确列出你的生产域名。空或通配符源列表让攻击者能够创建与你的后端通信的伪造 Clerk 前端。
  4. 在任何离职或疑似泄漏时轮换秘密密钥。仪表板 → API Keys → Reset。旧密钥失效;在轮换前用新值重新部署服务端代码。

会话配置

会话过期和闲置超时是被盗会话变成 10 分钟事件还是 30 天事件的差别。

  1. 对处理敏感数据的 SaaS 应用,将会话闲置超时设置为 30 分钟或更少。仪表板 → Sessions → Inactivity timeout。银行级应用应使用 5-10 分钟;标准 SaaS 30-60 分钟;消费者应用 1-7 天。默认为 7 天。
  2. 在密码更改、电子邮件更改和 MFA 注册时启用会话撤销。仪表板 → Sessions → Revoke on。这些是用户发起的安全事件;其他设备上的现有会话应被终止。
  3. 在每条受保护路由上验证服务端会话,而不仅是在登录时。在 Next.js 中:服务器组件 / API 路由中的 const { userId } = await auth(); 从 cookie 读取 JWT 并验证它。绝不信任仅 cookie 的检查。
  4. 在会话 cookie 上设置 SameSite=Lax (默认) 或 Strict在 DevTools → Application → Cookies 中验证。SameSite=None 是 CSRF 向量 — 除非你明确配置了跨域身份验证设置,否则绝不使用。

Webhook 验证

Clerk webhook 在用户生命周期事件 (创建、更新、删除、session.ended) 上触发。它们是你数据库的同步机制 — 而伪造的 webhook 是一种数据库写入原语。

  1. 对每个 webhook 验证 Svix 签名。Clerk webhook 由 Svix 签名。使用 new Webhook(secret).verify(body, headers)。验证失败时用 401 拒绝。
  2. 将 webhook 密钥存储在环境变量中,绝不在代码中。密钥在每次仪表板重新生成时轮换 — 你的部署必须从 env 读取它,而非常量。
  3. 每个处理程序都要幂等。Webhook 投递可能重复。在 webhook_events 表中使用 svix-id 标头作为主键来去重。在同一事务中包装状态变更和幂等插入。
  4. user.deleted 上,24 小时内硬删除或匿名化 PII。GDPR / CCPA 要求这样做。审计删除路径:哪些表持有此用户的数据?在可能的地方使用 FK ON DELETE CASCADE。

组织和权限

如果你使用 Clerk Organizations,组织边界就是你的租户隔离。每个服务端查询都必须按它过滤。

  1. 在每条 API 路由上,从 auth() 读取 userIdorgId 并按两者过滤数据库查询。 WHERE org_id = $orgId AND user_id = $userId。绝不信任来自请求正文的 org_id
  2. <strong>Use Clerk role checks for privileged operations, not boolean checks against the user object.</strong> <code>has({ role: 'org:admin' })</code> reads the role from the verified JWT. A user can spoof a boolean on a stale client object; they cannot spoof a JWT claim.
  3. 用两个真实组织账户测试跨组织隔离。创建组织 A,填充数据,在另一浏览器中登录组织 B,尝试通过 API 读取组织 A 的数据。响应必须是 403404

JWT 模板和外部集成

JWT 模板将 Clerk 身份推送到 Supabase、Firebase 和其他下游服务。配置错误的模板过度共享声明或暴露你未打算暴露的数据。

  1. 对每个 JWT 模板,列出每个声明并确认其必要性。仪表板 → JWT Templates。向 Supabase 发送 emailphone 的模板会向浏览器中读取 JWT 的任何人暴露 PII。
  2. 对用于客户端下游调用的 JWT 模板设置短过期时间。下游 API 请求 60 秒是标准。长寿命 JWT 会被盗并重放。
  3. 在接收端验证受众 (aud) 声明。Supabase、Firebase 等应检查 aud 是否与预期服务标识符匹配。没有这个,为服务 A 发行的 JWT 可以认证到服务 B。

运营监控

身份验证是你拥有的最高信号日志源。监视它。

  1. 对每 IP / 每账户的登录失败激增告警。正常失败率的 50 倍是凭据填充攻击。Clerk 将这些事件发出到 webhook;将它们路由到你的 SIEM。
  2. 季度审查会话和实例设置漂移。随着 Clerk 更新,默认值会变;「旧配置」会随时间悄悄变错。将仪表板 JSON 导出与你上一个已知良好副本做差异比较。

后续步骤

对你的生产 URL 运行 FixVibe 扫描 — baas.clerk-auth0 检查会标记 Clerk 可发布密钥、生产中的测试密钥和打包的秘密密钥。有关 Auth0 上的等效清单,请参阅 Auth0 安全清单。对于 BaaS 提供商的总览,请阅读 BaaS 配置错误扫描器

// 扫描你的 baas 面

在其他人之前找到开放的表。

输入一个生产 URL。FixVibe 会列举你的应用通信的 BaaS 提供商,识别它们的公共端点,并报告未经身份验证的客户端可以读取或写入什么。免费,无需安装,无需信用卡。

  • 免费层 — 每月 3 次扫描,注册无需信用卡。
  • 被动 BaaS 指纹识别 — 无需域名所有权验证。
  • Supabase、Firebase、Clerk、Auth0、Appwrite 等。
  • 每项发现都附带 AI 修复提示 — 可粘贴回 Cursor / Claude Code。
Clerk 安全清单:20 项 — Docs · FixVibe