2019年正确实现双因素认证 - Trail of Bits博客
William Woodruff
2019年6月20日
认证, 生态系统安全, 工程实践
自3月以来,Trail of Bits一直与Python软件基金会合作,为Warehouse(PyPI的代码库)添加双因素认证(2FA)。截至目前,PyPI成员可以启用基于时间的OTP(TOTP)和WebAuthn(当前处于测试阶段)。如果您在PyPI上有账户,请在继续阅读之前启用您偏好的2FA方法!
2018年和2019年是双因素认证的重要年份:
- W3C和FIDO在3月份最终确定了Level 1 WebAuthn规范。Chrome和Firefox已经对其提供了成熟支持,Safiri预计也会跟进。
- 即将发布的Android版本将允许用户使用手机作为安全密钥,iOS预计也会这样做。
- CTAP2标准的进展继续。虽然WebAuthn不需要CTAP2,但未来的WebAuthn设备将受益于其传输和认证器配置改进。
- 主要网站已开始 discouraging 使用SMS和语音代码,这些作为第二因素已被彻底破坏。Google现在允许G-Suite管理员强制执行无SMS的2FA,防止用户向其2FA方法添加弱链接。
总的来说,现在是为您的服务添加2FA的最佳时机。继续阅读以了解如何正确实施。
什么是2FA,什么不是
在讨论实施双因素认证的正确决策之前,理解第二因素是什么和不是什么至关重要。
特别是:
- 第二因素方法不应是可知道的。第二因素方法是用户拥有或是什么,而不是用户知道什么。
- 第二因素方法不应替代用户的第一因素(通常是密码)。因为它们是用户拥有或是什么,它们是身份证明。WebAuthn是此规则的部分例外:由于其更强的保证,它可以作为单因素使用。
- 第二因素方法可按安全性排序。特别是,WebAuthn总是优于TOTP,因此启用了两者的用户应首先被提示使用WebAuthn。不要让用户默认使用安全性较低的第二因素。如果您出于遗留原因支持SMS作为第二因素,请告知用户一旦添加了更好的方法就可以移除它。
- 2FA实现不应在第一因素之前请求用户的第二因素。这对于TOTP来说无论如何都不可行,但您可能会 tempted 使用WebAuthn凭据的ID或公钥这样做。这本身不会引入安全风险,但不一致的排序只会混淆已经难以理解其安全密钥在认证中作用的用户。
- 恢复代码应可用,并且应为偏好其账户失败致命的用户提供足够警告的选择退出。恢复代码不是第二因素——它们绕过了2FA方案。然而,用户不理解2FA(见下文),如果没有直接的恢复方法,他们会出于沮丧而禁用它。当安全存储时,恢复代码代表了可用性和2FA方案健全性之间的可接受折衷。
您的用户不理解2FA,并会尝试破坏它
用户,即使是极其技术性的用户(如平均PyPI包维护者),也不理解2FA或其约束。他们会在不同程度下:
尝试行为 | 风险 | 补救措施 |
---|---|---|
截图其TOTP QR码并留在Downloads文件夹中 | 暴露TOTP密钥 | 文档:警告用户不要保存QR码 |
使用相同的QR配置多个TOTP应用 | 对其第二因素是什么/在哪里理解不足 | 文档:告知用户只配置一个设备 |
使用允许将代码导出为未加密文本的TOTP应用 | 暴露TOTP密钥;不安全的密钥管理 | 文档:建议不支持未加密导出的TOTP应用 |
使用损坏的TOTP应用或不尊重TOTP参数的应用 | 不正确的TOTP代码生成;应用中混淆的TOTP标签 | 几乎没有:几乎每个TOTP应用都忽略或施加额外约束。使用默认配置参数! |
用错误的应用扫描TOTP QR | 丢失第二因素;无法登录 | 要求在接受配置请求之前输入TOTP代码 |
尝试手动输入配置URI或密钥并出错 | 丢失第二因素;无法登录 | 同上;要求TOTP代码完成配置 |
错误标记其TOTP登录并混淆 | 错误标记的第二因素;无法登录 | 提供otpauth支持的所有用户名和发行者名字段。劝阻用户使用仅支持服务白名单或需要手动标记的TOTP应用 |
在您的服务之前从其应用中删除TOTP密钥 | 账户锁定 | 文档:警告用户不要这样做,并推荐提供类似警告的TOTP应用 |
将恢复代码保存到桌面上的文本文件 | 第二因素绕过 | 使恢复代码选择加入,并告知用户只保存恢复代码的打印副本 |
混淆不同服务的恢复代码 | 丢失绕过;无法登录 | 在恢复代码前添加站点名称或其他区分标识符 |
完全忽略其第二因素,只使用恢复代码 | 不是真正的2FA | 跟踪恢复代码使用并警告重复违规者 |
尝试使用其旧的RSA SecurID、奇怪的企业HOTP fob或pre-U2F密钥 | WebAuthn不支持 | 在配置失败时提供明确错误。大多数浏览器应对pre-U2F密钥这样做 |
混淆其硬件密钥 | 错误标记的第二因素;无法登录 | 让用户能够在您的服务上用人性化名称标记其注册密钥,并鼓励他们物理标记 |
给予或转售其硬件密钥而不取消配置 | 第二因素泄露 | 文档:警告用户不要这样做。对于更激进的安全,挑战他们在某些间隔内断言其每个WebAuthn凭据 |
技术用户可能更糟:在撰写本文时,一位熟人讲述了一个使用Twilio和通知推送服务绕过其大学基于SMS的2FA的故事。
这些场景中的许多部分不可避免,并非所有都从根本上削弱或威胁削弱您的2FA设置的健全性。然而,您应意识到每一个,并寻求尽可能用户证明您的方案。
WebAuthn和TOTP是您唯一需要的
您不需要SMS或语音代码。如果您目前出于遗留原因支持SMS或语音代码,那么您应该:
- 防止新用户启用它们,
- 告知当前用户移除它们并切换到WebAuthn或TOTP,以及
- 对仍启用SMS和/或语音代码的用户执行额外日志记录和警报。
偏执?是的。但如果您持有任何加密货币,您可能应该偏执。
过度?也许。SIM端口攻击仍然相对不常见(且有针对性),尽管几乎不需要技术技能。通过SMS或语音代码进行2FA仍然比完全没有好。Google自己的研究表明,仅SMS就能防止几乎所有非针对性钓鱼攻击。针对性攻击的数字更 bleak:近四分之一的针对性攻击对仅基于SMS的2FA用户成功。
担心除了SMS之外的其他方法不实用和/或昂贵?不要担心。有大量免费的TOTP应用适用于iOS和Android。在WebAuthn方面,Google将以50美元的价格向您出售包含两个安全密钥的套件。您甚至可以用25美元购买一个完全开源的密钥,该密钥将与WebAuthn配合使用!最重要的是:TOTP不如硬件密钥好的事实不是继续允许SMS或语音代码的借口。
对比TOTP和WebAuthn
TOTP和WebAuthn都是为您的服务添加2FA的可靠选择,如果有机会,您应该支持两者。以下是一些考虑因素:
TOTP是对称且简单的,WebAuthn是非对称且复杂的
TOTP是一种对称加密方案,意味着客户端和服务器共享一个密钥。这加上TOTP相对简单的代码生成过程,使其易于实现,但导致一些陷阱:
- 因为客户端需要存储对称密钥,TOTP的安全性仅与包含应用或设备一样安全。如果恶意程序可以提取用户的TOTP密钥,那么它们可以在用户不知情的情况下生成任意多个有效的TOTP代码。
- 因为TOTP中客户端和服务器之间共享的唯一状态是初始密钥和后续生成的代码,TOTP缺乏设备身份的概念。因此,信息不足的用户可以使用相同的密钥配置多个设备,增加其攻击面。
- TOTP不提供固有的重放保护。服务可能选择通过拒绝接受有效代码多次来防止重放,但这可能 ensnare 在TOTP窗口内多次登录的合法用户。
- 可能可暴力破解。大多数服务使用6或8位TOTP代码,并提供扩展的验证窗口以适应行动不便的用户(和时钟漂移),使在线暴力破解刚刚处于可行性边缘。解决方案:速率限制登录尝试。
以上所有因素结合使TOTP代码成为理想的钓鱼目标。私人和国家团体都成功使用假登录表单和其他技术成功欺骗用户共享其TOTP代码。
相比之下,WebAuthn使用非对称公钥加密:客户端在从服务器接收选项列表后生成密钥对,将公钥半部分发送到服务器用于验证目的,并安全存储私钥半部分用于认证期间的签名操作。这种设计导致 substantially 更复杂的证明模型,但产生许多好处:
- 设备身份:WebAuthn设备由其凭据ID标识,通常与人性化标签配对用于用户管理目的。WebAuthn的身份概念使得支持每个用户多个安全密钥变得容易——不要人为地将您的用户限制为每个账户单个WebAuthn密钥!
- 反重放和反克隆保护:设备注册和断言方法包括认证方生成的随机挑战,行为良好的WebAuthn设备在每次断言后发送更新的签名计数器。
- 来源和安全上下文保证:WebAuthn在设备注册和证明期间包括来源信息,并仅允许在安全上下文内进行交易,防止常见钓鱼向量。
TOTP是免费的,WebAuthn(目前大部分)不是
如上所述,有许多免费的TOTP应用,可用于您的用户将使用的几乎所有平台。几乎所有这些都支持Google的otpauth URI“标准”,尽管完整度/正确性程度不同。
相比之下,大多数WebAuthn的潜在用户将需要购买安全密钥。各种硬件密钥标准之间的关系令人困惑(并且可能占据整个单独的博客文章),但大多数U2F密钥应该是WebAuthn兼容的。然而,WebAuthn不仅限于安全密钥:如前所述,Google正在努力使其移动设备充当WebAuthn兼容的第二因素,我们希望Apple也在做同样的事情。一旦发生,许多用户将能够在没有额外购买的情况下切换到WebAuthn。
使用正确的工具
TOTP的简单性使其成为重新实现的有吸引力的目标。不要这样做——它仍然是一个密码系统,您永远不应自己编写加密。相反,使用成熟且抗误用的实现,如PyCA的hazmat.primitives.twofactor。
WebAuthn仍然相对较新,因此没有那么多服务器端实现可用。Duo的优秀人员正在努力补救这一点:他们已经开源了Go和Python库,并为用户和实现者提供了优秀的在线演示和文档。
从我们的工作中学习
想为您的服务添加2FA,但不知道从哪里开始?查看我们在Warehouse代码库中的TOTP和WebAuthn实现。
我们的公共接口有良好文档,并且(按照Warehouse标准)所有分支都有测试覆盖。支持多个WebAuthn密钥,并且将在不久的将来添加对可选恢复代码的支持。
如果您有其他更定制的加密需求,请联系我们寻求帮助。
如果您喜欢这篇文章,请分享: Twitter LinkedIn GitHub Mastodon Hacker News