You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

开发TOTP双因素认证:如何在数据库安全存储密钥?

安全存储TOTP密钥的可行方案建议

针对你开发基于TOTP的双因素认证系统时遇到的密钥存储难题,我结合实际生产经验给你几个可行的安全方案,帮你平衡安全性和可用性:

方案一:使用独立的系统级加密密钥(优先推荐)

既然哈希方案不可行(需要明文密钥计算TOTP),那最稳妥的方式是用与用户密码完全独立的系统级加密密钥来加密TOTP密钥。

  • 具体做法:

    1. 生成一个专门的主加密密钥,把它存储在安全的密钥管理服务(比如KMS)或者硬件安全模块(HSM)中,绝对不能和数据库一起存储,更不能硬编码在代码里。
    2. 当生成用户的TOTP密钥后,用这个主密钥对其进行加密(推荐用AES-GCM这种带认证的加密算法,既能加密又能防篡改),然后把加密后的密文存储到数据库。
    3. 验证TOTP时,从数据库取出密文,调用KMS/HSM解密得到明文密钥,计算验证码后立即从内存中清除密钥。
  • 核心优势:完全不受用户密码重置的影响,系统可以独立完成解密操作,不会因为用户改密码导致TOTP密钥失效。而且主密钥的权限可以严格管控,只有负责TOTP验证的服务能访问,降低泄露风险。

  • 注意事项:要定期轮换主密钥,每次轮换后需要重新加密所有用户的TOTP密钥(这个过程可以分批后台执行,不影响用户使用)。

方案二:混合加密(用户密码派生密钥 + 系统主密钥)

如果想兼顾用户密码的额外防护,同时避免密码重置的弊端,可以采用双重加密的思路:

  • 具体流程:

    1. 生成用户的TOTP密钥K
    2. 先用系统主密钥SM加密K,得到EK1
    3. 再用用户密码通过密码派生函数(比如Argon2idPBKDF2)生成用户专属密钥UK,用UK加密EK1得到最终的密文EK2,存储EK2到数据库。
    4. 验证时:用户输入密码生成UK,解密EK2得到EK1,再用SM解密EK1得到K,计算TOTP验证码。
    5. 密码重置时:先通过其他身份验证方式(比如邮箱验证码、短信验证)确认用户身份,然后用新密码生成新的UK',重新加密EK1EK1可以临时存储在安全的缓存中,或者重新用SM加密原密钥K生成),替换数据库中的EK2即可。
  • 核心优势:双重加密提供了两层防护,即使其中一层密钥泄露,也不会直接暴露TOTP密钥;同时完美解决了密码重置后无法解密的问题,不需要用户重新绑定TOTP。

方案三:用户密码派生密钥 + 备份机制(备选)

如果坚持想只用用户密码派生的密钥加密TOTP密钥,那必须配套完善的密钥备份机制:

  • 具体做法:

    1. 用户设置TOTP时,除了用密码派生密钥加密密钥存储,还要生成一个备份版本——用系统主密钥加密原TOTP密钥,把这个备份密文存储在独立的安全存储中(比如单独的加密数据库或者KMS)。
    2. 当用户重置密码后,先通过严格的身份验证(比如人工审核、多渠道验证)确认身份,然后取出备份的密文,用系统主密钥解密得到原TOTP密钥,再用新密码派生的密钥重新加密后存储到数据库。
  • 注意事项:备份的密文必须严格限制访问权限,恢复过程要做详细的审计日志,防止被滥用。

通用安全实践补充

不管采用哪种方案,这些细节都不能忽略:

  • TOTP密钥在内存中处理时,要尽量缩短存活时间,计算完验证码后立即从内存中清除(比如用覆盖内存的方式,避免被内存dump泄露)。
  • 数据库中存储的加密后的TOTP密钥,不要和用户密码哈希等敏感信息放在同一个表分区,最好分开存储,降低批量泄露的风险。
  • 对所有加密、解密操作做审计日志,记录操作时间、操作人、用户ID等信息,方便追踪异常行为。

内容的提问来源于stack exchange,提问作者Dev0r

火山引擎 最新活动