双因素认证与密码安全最佳实践
你已经构建了一个 Web 应用,用户正在注册。但他们的账户真的安全吗?弱密码和缺少双因素认证(2FA)是攻击者最容易入侵的途径之一。在本指南中,我们将介绍实用且长期有效的密码安全和 2FA 最佳实践,你可以立即实施。
为什么密码安全仍然重要
尽管多年来不断有警告,密码仍然是大多数 Web 应用的主要身份验证方式。攻击者深知这一点,并通过网络钓鱼、凭据填充和暴力破解来攻击密码。一个被泄露的密码就可能导致账户接管、数据窃取和声誉损害。
强密码策略和 2FA 能显著提高攻击者的门槛。让我们看看如何正确实施这两者。
密码存储:正确进行哈希
切勿以明文存储密码。始终使用专为密码设计的强慢哈希算法进行哈希。像 SHA-256 这样的快速哈希算法不适合,因为它们会助长快速暴力破解攻击。
推荐的算法:
- Argon2id – 密码哈希竞赛的获胜者,能抵抗 GPU 和侧信道攻击。
- bcrypt – 广泛支持、久经考验,且设计上就是慢的。
- scrypt – 内存硬算法,适合防止硬件加速攻击。
在 Node.js 中使用 bcrypt 的示例:
const bcrypt = require('bcrypt');
const saltRounds = 12;
async function hashPassword(password) {
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
始终为每个密码使用唯一的盐(大多数库会自动处理)。调整成本因子,使哈希在你的服务器上耗时约 100-500 毫秒。
真正有用的密码策略
忘掉“必须包含符号和数字”这类复杂规则。现代指南(NIST SP 800-63B)建议:
- 最小长度为 8 个字符,但鼓励使用密码短语(例如 4 个以上随机单词)。
- 对照已泄露密码列表进行检查(例如 Have I Been Pwned API)。
- 除非怀疑账户被入侵,否则不强制定期过期。
- 允许所有可打印的 ASCII 字符和空格。
- 对登录尝试进行速率限制,以防止暴力破解。
实现一个简单的强度指示器,在不阻止合法密码的情况下给出反馈。
双因素认证(2FA)方法
2FA 增加第二个因素:你拥有的东西(手机、硬件密钥)或你本身(生物特征)。以下是按安全性排序的常见方法:
| 方法 | 安全性 | 可用性 |
|---|---|---|
| 硬件安全密钥(WebAuthn/FIDO2) | 高 | 中 |
| 认证器应用(TOTP) | 高 | 高 |
| 推送通知 | 中 | 高 |
| 短信验证码 | 低 | 高 |
短信容易受到 SIM 卡交换和拦截攻击。尽可能优先使用 TOTP 或 WebAuthn。
实现基于 TOTP 的 2FA
TOTP(基于时间的一次性密码)在安全性和可用性之间取得了很好的平衡。以下是一个高层工作流程:
- 为用户生成一个密钥(例如 32 个随机字节,base32 编码)。
- 创建一个 otpauth:// URI 并显示二维码,供用户使用认证器应用扫描。
- 在启用 2FA 之前,验证用户能否生成有效验证码。
- 安全地存储密钥(静态加密)。
- 提供备用代码用于账户恢复。
登录时,在验证密码后,提示输入 TOTP 验证码。使用 otplib 或 speakeasy 等库进行验证。
const { authenticator } = require('otplib');
// 生成密钥
const secret = authenticator.generateSecret();
// 验证令牌
const isValid = authenticator.verify({ token: userToken, secret });
允许一个较小的时间窗口(例如 ±1 个间隔),以应对时钟漂移。
WebAuthn:身份验证的未来
WebAuthn(FIDO2 的一部分)支持使用硬件密钥或平台认证器(Touch ID、Windows Hello)进行无密码和双因素认证。它具有抗网络钓鱼能力,因为凭据绑定到源。
实现 WebAuthn 需要:
- 服务器端生成和验证挑战。
- 客户端 JavaScript 使用 WebAuthn API。
- 为每个用户存储公钥和凭据 ID。
像 SimpleWebAuthn 这样的库可以简化实现。虽然比 TOTP 更复杂,但 WebAuthn 提供了最强的保护。
速率限制和账户锁定
即使有 2FA,也必须防止对密码的暴力破解攻击。实施:
- 按 IP 和按账户的速率限制(例如每分钟 5 次尝试)。
- 失败尝试后的指数退避。
- 重复失败后锁定账户,并采用安全的解锁流程(例如电子邮件验证)。
- 几次失败后启用 CAPTCHA。
注意不要永久锁定合法用户;使用临时锁定并通知用户。
安全的密码重置
密码重置流程是常见的攻击媒介。遵循以下规则:
- 使用通过电子邮件发送的一次性、有时间限制的令牌。
- 不要透露系统中是否存在某个电子邮件。
- 如果用户已登录,要求重新进行身份验证。
- 密码重置后使所有会话失效。
教育用户,而非指责他们
安全是共同的责任。提供清晰的指导:
- 使用密码管理器生成并存储唯一密码。
- 尽可能启用 2FA。
- 警惕网络钓鱼企图。
应用内提示和专门的安全页面会有所帮助。
常见问题
基于短信的 2FA 比没有 2FA 更好吗?
是的,短信 2FA 比没有好,但它容易受到 SIM 卡交换和拦截攻击。为了更强的安全性,优先使用 TOTP 或 WebAuthn。
我应该多久轮换一次密码哈希算法?
除非发现漏洞,否则不需要轮换。但是,当你升级参数(例如增加 bcrypt 成本)时,可以在成功登录时重新哈希密码。
我可以将 2FA 与 OAuth 或社交登录一起使用吗?
可以,但 2FA 通常由身份提供商管理。如果你使用社交登录,请确保你自己的账户恢复流程是安全的。
准备好增强你的应用安全性了吗?从今天开始实施强密码哈希和基于 TOTP 的 2FA。如需更多开发者工具,请查看我们的 JSON Formatter 以快速调试 API 响应。