Skip to content

feat(captcha)!: 加固验证码场景绑定与原子消费 - #133

Open
zzswang wants to merge 2 commits into
mainfrom
feat/captcha-scoped-consumption
Open

feat(captcha)!: 加固验证码场景绑定与原子消费#133
zzswang wants to merge 2 commits into
mainfrom
feat/captcha-scoped-consumption

Conversation

@zzswang

@zzswang zzswang commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

验证码此前只校验 key 与答案,缺少账号和用途绑定,并发消费可能重复成功。本次将图形、短信和邮箱验证码统一绑定 kind、purpose、subject,通过 MongoDB 原子消费和 Redis 滚动限流限制重放及暴力尝试。

这个 PR 完成了:

  • 服务端生成签发 key,重发原子替换旧码;按类型设置有效期、失败次数上限及签发/校验限流,限流返回 429 + Retry-After,依赖故障返回 503
  • 手机和邮箱登录、自动注册、独立注册及密码重置按固定场景消费验证码;业务失败或响应丢失后不恢复已消费验证码。
  • 新增 @loginByCode@registerByCode,通过 channel=sms/emailaccount 统一验证码登录与注册。原有四个 byPhone / byEmail 接口保持兼容,与新入口共用内部流程。
  • @registerByCode 支持可选密码,校验通过后复用现有密码哈希与更新时间逻辑;注册返回 User,之后可用手机号或邮箱加密码登录。旧注册入口不增加密码字段。
  • 验证码在数据库中明文保存,仅签发响应返回答案,成功消费时清除;查询只返回元数据,无需 CAPTCHA_HMAC_SECRET
  • 短信和邮件记录仅保存元数据,CRUD 不再保存或返回短信参数、邮件标题和正文;清除相关敏感日志和完整供应商异常输出。
  • 提供幂等迁移脚本、接入文档、OpenAPI 及安全测试;修正第三方接口响应注解和缺少 .npmrc 时的 SDK 生成问题,CI 增加安全测试与 SDK 类型检查。

发布建议

  • 验证码安全协议为不兼容升级,auth 与业务后端需同步切换。 签发和验证必须提供 kind、purpose、subject@verifyCaptcha 成功即消费;删除接口传签发 key;移除 PATCH。图形验证码应在对应业务操作中消费。
  • CAPTCHA_POLICY_JSONCAPTCHA_REDIS_PREFIX 可省略,使用服务端默认值;各实例保持相同策略和 Redis 前缀。原 CAPTCHA_EXPIRES_IN_SCAPTCHA_CODE_LENGTH 不再使用。
  • 先执行 pnpm migrate:captcha-security 只读统计;切换窗口暂停验证码及相关发送入口、停止旧实例写入后,执行 CAPTCHA_MAINTENANCE_MODE=true pnpm migrate:captcha-security --execute,再部署新版本与调用方。
  • 迁移清理旧验证码、历史短信 params 和邮件 subject/content,建立新的唯一索引及 TTL 索引;脚本可重复执行。生产迁移尚未执行。
  • 新增统一登录/注册接口本身为兼容增量,不需要额外数据迁移;服务端部署后调用方可按需迁移,旧认证接口不设移除时间。
  • 业务入口继续承担真实 IP、匿名会话、实际发送次数和供应商费用限流;auth 签发配额不等于实际发送配额。

验证

  • 提交钩子:lint、全量 95 项单测通过,其中包含 44 项安全相关测试。
  • 45 项集成测试通过,覆盖新旧入口兼容、自动注册、可选密码与密码登录、字段校验、场景绑定、跨入口重放、禁用用户和限流响应。
  • build、OpenAPI 生成、SDK 生成与 TypeScript 检查通过;统一接口新增前后的原有 OpenAPI 路径和数据结构逐项对比一致。
  • 测试使用临时 MongoDB、专用 Redis 键和模拟发送器,未发送真实短信或邮件。

相关资料

Add server-generated issuance keys, scoped verification, attempt limits and Redis rolling quotas.
Consume challenges atomically and expose answers only in issuance responses while retaining
plaintext database storage.

Keep SMS and email records metadata-only, remove sensitive logs, and add migration tooling,
integration coverage, API documentation and SDK checks.

BREAKING CHANGE: captcha creation and verification require kind, purpose and subject.
Verification consumes the challenge, DELETE uses the issuance key, and PATCH is removed.
Callers and auth must migrate together and invalidate legacy challenges.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant