如何为应用添加双重验证
要为你的应用添加双重验证(2FA),可以让用户通过扫描二维码绑定一个验证器应用,在输入密码之后要求他们输入该应用显示的六位数字验证码,并且只有在验证码校验通过后,才在服务端创建完整会话。用户启用 2FA 时,应向其提供一次性恢复码;限制任何人可以尝试猜测验证码的次数;并且在关闭 2FA 之前,要求同时输入密码和当前验证码。如果你使用托管的认证服务商,则应开启其内置的多因素认证选项,而不是自己构建。
本指南会介绍各种选择、具体流程、可以提供给 AI 构建工具的提示词,以及那些会让 2FA 看似已启用、实际上却毫无作用的常见错误。如果你对这个概念还不熟悉,请先阅读什么是双重验证。
开始之前:你需要一个可用的登录系统
2FA 是构建在现有登录之上的。你首先需要以下两者之一:
- 你自己的登录系统,用户和经过哈希处理的密码保存在应用的数据库中。
- 托管的认证服务商,由它替你管理用户。
如果两者都还没有,请先从如何为应用添加登录功能开始。本指南其余部分假设密码验证步骤已经可以正常工作。
选择第二重验证方式
| 方式 | 用户操作成本 | 安全性 | 运行成本 | 是否适合作为默认方式 |
|---|---|---|---|---|
| 验证器应用(TOTP) | 扫描一次二维码,登录时输入验证码 | 良好;如果假网站索要验证码,仍可能被钓鱼 | 免费 | 对大多数应用而言适合 |
| 通行密钥或安全密钥 | 轻触或使用指纹 | 最强;可抵御钓鱼 | 免费 | 如果用户愿意使用,则适合 |
| 邮件验证码 | 登录时查看收件箱 | 强度仅取决于该邮箱账户 | 邮件发送费用 | 仅作为备用方式 |
| 短信验证码 | 等待短信 | 最弱;存在 SIM 卡交换和钓鱼风险 | 按条收费 | 仅当用户无法使用应用时 |
TOTP 代表基于时间的一次性密码,是验证器应用所使用的标准(RFC 6238)。你的服务端和用户的手机共享一个密钥;双方根据该密钥和当前时间生成相同的短验证码,通常每 30 秒更换一次。不需要网络连接,也不需要短信服务商。
通行密钥使用存储在用户设备上的加密密钥来取代或补充密码。它们更安全,但自己构建的工作量更大,因此许多应用先使用 TOTP,之后再添加通行密钥,或者直接从认证服务商获取。
自己构建还是直接开启?
| 方式 | 优点 | 缺点 |
|---|---|---|
| 托管认证服务商的 MFA | 代码更少;安全细节由服务商维护 | 规模化后需要按月付费;依赖服务商提供的选项 |
| 使用库自行实现 TOTP | 完全可控;没有按用户收费 | 边界情况需要你自己处理:锁定、恢复、密钥存储 |
请查阅你的服务商当前的文档,了解其支持哪些验证方式以及在哪些套餐中可用。无论选择哪种方式,都不要自己编写验证码生成的算法;应使用广泛使用的成熟库。
先确定策略
在编写提示词之前先回答以下问题,因为它们会改变设计:
- **谁必须使用它?**对所有人可选,对管理员和员工必须启用,还是对所有人强制启用?对拥有管理权限的人强制启用是常见做法。参见基于角色的访问控制。
- **用户多久需要重新输入一次验证码?**每次登录都需要,还是每台设备 30 天内只需一次(“记住此设备”)。
- **哪些操作需要重新验证?**更改邮箱、收款信息或关闭 2FA 都是很好的候选。这被称为“提升验证(step-up authentication)”。
- **手机丢失后的流程是什么?**恢复码,以及你愿意执行的人工备用流程。
分步操作:在你自己的登录系统上实现 TOTP 2FA
1. 存储正确的字段
每位用户需要:是否启用了 2FA、TOTP 密钥(静态加密,而不是明文)、启用的时间,以及一份以哈希形式存储的恢复码列表,就像密码一样。还需要一个用于记录失败尝试次数的地方。
2. 注册流程
- 用户打开设置,点击开启双重验证。
- 服务端生成一个新密钥,并以二维码形式返回,同时提供文本版本,供无法扫码的人使用。
- 用户在验证器应用中扫描它,并输入当前的验证码。
- 服务端校验验证码。只有验证码正确,才保存密钥并将 2FA 标记为已启用。
- 应用只展示一次 8–10 个恢复码,并提示用户保存好。
第 4 步很关键:如果在确认验证码之前就开启了 2FA,那么扫描失败的人将被锁在账户之外。
3. 带第二步的登录
- 用户提交邮箱和密码,服务端进行校验。
- 如果启用了 2FA,服务端不会立即创建完整会话,而是创建一个短期有效的“等待第二重验证”状态。
- 应用显示验证码输入界面。服务端校验验证码,并为时钟偏差保留一个小的时间窗口。
- 只有到这一步,服务端才会签发真正的会话。
每一条受保护的路由和 API 端点都必须拒绝“等待第二重验证”状态。如果 2FA 页面只是在浏览器中隐藏了页面,那么直接调用 API 就能绕过它。
4. 限制与提醒
六位数字验证码共有一百万种组合,如果没有限制,很容易被猜中。应限制尝试次数,在多次失败后将第二步锁定一段时间,并在发生这种情况时向用户发送邮件。参见速率限制和从应用发送邮件。
5. 恢复与关闭
- 每个恢复码只能使用一次,使用后即被删除。
- 关闭 2FA 需要密码以及当前验证码或恢复码。
- 重新生成恢复码会使旧的一组失效。
- 每当开启或关闭 2FA 时,都向用户发送邮件通知。
给 AI 构建工具的提示词
先从核心流程开始:
为我们现有的邮箱和密码登录添加可选的双重验证,使用验证器应用(TOTP)。使用成熟的 TOTP 库,不要自己编写算法。在设置中展示二维码和文本密钥,并且只有在用户输入有效验证码后才启用 2FA。密钥加密存储,设置完成后不再显示。一次性展示 10 个一次性恢复码,并以哈希形式存储。
然后是强制执行,这也是生成的代码最常出问题的地方:
在服务端强制执行 2FA。密码正确之后,启用了 2FA 的用户进入短期的“等待”状态,而不是完整会话。每一条受保护的页面和 API 路由都必须拒绝该等待状态。验证码尝试次数限制为 5 次,然后将第二步锁定 15 分钟,并向用户发送邮件。
接着是策略:
要求管理员账户启用 2FA:未启用 2FA 的管理员会被引导到设置页面,直到完成设置前无法进入仪表盘。关闭 2FA 或更改账户邮箱时,需要同时输入密码和当前验证码。在 2FA 被启用或关闭时向用户发送邮件。
最后,请代理解释它构建了什么:
列出所有检查第二重验证是否已完成的路由,说明 TOTP 密钥和恢复码存储在哪里,以及它们如何受到保护。
常见错误
- **输入密码之后就签发会话。**这是最严重的漏洞。如果在验证码检查之前就已存在完整会话,2FA 就只是摆设。测试方法:只完成密码步骤后,直接调用一个受保护的 API。
- **没有尝试次数限制。**无限次猜测会让验证码可以被暴力破解。
- **密钥或恢复码以明文存储。**数据库一旦泄露,所有人的第二重验证就等于被交了出去。
- **未验证就启用。**扫码出错的用户在下次登录时会被锁定。
- **没有恢复途径。**每一次手机丢失都会变成一张支持工单,或者一位流失的客户。
- **关闭 2FA 过于容易。**如果被盗的会话无需验证码就能关闭 2FA,那么保护也就不复存在了。
- **验证码出现在日志中。**确保验证码和密钥绝不会出现在服务端日志或错误信息中。
- **只在登录页面检查。**密码重置、“魔法链接”登录以及任何第三方社交登录都必须同样遵守 2FA,否则它们就会成为绕过 2FA 的途径。
测试清单
- 只有在输入有效验证码之后,注册才会完成
- 密码正确但没有验证码时,无法访问任何受保护的页面或 API
- 错误的验证码会被拒绝;多次输入错误验证码会触发锁定并发送邮件
- 几分钟前的验证码会被拒绝
- 每个恢复码只能使用一次
- 关闭 2FA 需要密码和当前验证码
- 密码重置不会绕过 2FA
- (如果要求)未启用 2FA 的管理员无法进入管理页面
- 密钥和恢复码在数据库中已加密或哈希处理
- 日志中不会出现任何验证码或密钥
上线前,也请完整执行一遍AI 构建应用安全检查清单。
在 Mythex 中添加 2FA
Mythex 不为你应用的最终用户提供内置的登录系统,因此 2FA 属于你所选择的任何认证方式的一部分:可以是使用项目数据库的你自己的邮箱和密码登录,也可以是支持多因素认证的托管服务商。你可以使用上面类似的提示词在对话中描述需求;任何服务商密钥都应放在项目机密中(通过 /secrets、项目设置或代理显示的机密卡片),而不是放在消息框中。文档中的为应用添加登录功能配方提供了入门提示词,为你构建的应用设置安全则涵盖了与密钥和权限相关的良好习惯。代理完成后,请在发布之前,在预览中逐项测试检查清单上的每一条。
常见问题
为应用添加双重验证最简单的方法是什么?
如果你使用托管的认证服务商,只需开启其内置的多因素认证选项,通常所需代码最少。如果你自己运行登录系统,则需要借助成熟的库添加验证器应用验证码(TOTP),并配合恢复码和服务端检查。
双重验证应该使用短信验证码吗?
短信总比没有第二重验证好,但它是常见选项中最弱的一种,因为短信可能通过 SIM 卡交换被劫持,验证码也可能遭到钓鱼。建议默认提供验证器应用,并在用户准备好的情况下提供通行密钥。
添加 2FA 需要数据库吗?
如果你自己运行登录系统,那么需要。每位用户的 2FA 密钥、是否启用了 2FA,以及他们经过哈希处理的恢复码,都必须保存在服务端可以检查的地方。托管的认证服务商会替你保存这些信息。
如果用户丢失了手机怎么办?
他们可以使用启用 2FA 时展示的某个一次性恢复码登录,然后在新设备上重新设置 2FA。如果没有恢复码,就需要进行人工身份核实,因此请在上线前确定这一流程。