delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

23 May 2023

关掉了 Google 账户的 passkey

最近, Google 账户新增了一种叫做 passkey 的登录方式。

传统的采用密码登录的登录方式中,用户需要用某种方式证明自己知道密码,而绝大多数实现中这意味着网站必须保存用户的密码, 或是密码的 hash 值(通常是HMAC),这意味着网站如果发生了拖库的情况,有可能会将用户的密码或其 hash 值泄漏出去。 此外,用户可能必须输入密码,并将密码通过某种方式传输到服务器上,这样一来在这个过程中便有可能由于本地的木马, 或是网站采用的 SSL/TLS 实现的漏洞导致密码泄漏。除此之外,即使用户十分小心地在每一个不同的网站都使用了不同的密码, 他们仍然需要担心被「钓鱼」的问题,所谓「钓鱼」是这样一种攻击方式:攻击者架设一个看起来很像是用户希望登录的网站的网站, 并诱骗用户输入密码。

许多网站提供了二次认证的功能。在二次认证中,用户除了密码之外还需要一个能够证明是其本人进行操作的东西再确认一次身份。 采用过时技术的网站往往会使用 SMS 短信进行二次认证,很明显,这种方式并不能彻底阻止「钓鱼」攻击: 攻击者通过架设一个假的网站诱使用户输入密码之后,可以直接模拟用户的操作去向真正的网站提出请求, 并要求用户输入收到的短信中的数字。更为严重的是,采用 SMS 短信进行二次认证时,用户手机的安全性也十分重要, 对于一些高价值的受害人来说,攻击者完全可以设法欺骗运营商让它们把用户的短信发到自己控制的SIM卡上, 从而收到这些验证短信,并利用之前钓鱼获得的密码完成登录。

与此类似,使用 TOTP (例如 Google Authenticator)作为 2FA 尽管不会有短信那样的安全问题, 但也无法彻底杜绝「钓鱼」攻击。

为了解决这个问题,Google 和 Yubico 提出了采用 U2F 作为 2FA。在这种验证模式通过公钥密码学的方法,在用户硬件上保存一个私钥,而网站只保存用来验证它的公钥。 在验证时,网站和用户采用挑战-应答认证,网站每次生成不同的挑战值,而用户用私钥签名,从而避免了同一数值被多次使用。 更进一步,在这个设计中,网站的 URL 作为 application ID, 大幅提高了制作钓鱼网站的门槛(想要成功的攻击,不仅需要制作一个样子类似的网站,还得能成功劫持域名; 如果只是注册一个域名类似的网站进行钓鱼,则无法获得正确的 U2F 应答)。

前面说了这么多,passkey 又是什么呢?和 U2F 的工作方式类似,passkey 同样使用了公钥密码学的方法,将公钥交给网站。 目前最新版本的 Apple iOS 和 Google 的 Android 上都完全实现了 passkey。其中, Apple 的实现会将 passkey 自动通过 iCloud Keychain 同步到所有登录了同一个 Apple ID 的支持该功能的 iOS 设备, 与其密码管理器类似,这些 passkey 受生物信息(指纹或刷脸)保护,并可使用屏幕解锁密码来解锁。 Android 的实现与此类似,通过 Password Manager 同步,可以用生物信息或屏幕解锁密码来解锁, 而登录 Google 账户时,Android 会自动生成一个 passkey,在 Google 账户中不能将其删除。

总体上,passkey 要比密码要安全得多:首先,采用公钥密码学的方法进行验证,意味着网站只掌握用于确认用户身份的公钥, 即使发生数据泄漏,该数据对于攻击者来说也只是能用来验证发到这个网站的用户回应是否是由用户私钥签署, 其危害远小于泄漏的密码或密码的hash。其次,passkey 可以提供比密码多得多的熵,并且无需记忆。 最后,passkey 的验证回应只会发给域名能匹配的上的网站,从而杜绝了钓鱼。

不过,我认为和 密码 + U2F 的验证方式相比,passkey 实际上类似于在手机等设备上实现了一个 U2F, 并使用它代替了两者的组合。对于普通用户来说这固然是比只用密码要安全的多的(因为 passkey 证明了用户拥有一个登录了该 Apple ID 或 Google 账户的设备,并且知道其解锁密码, 或是向设备以生物信息证明了身份),但由于完全去掉了密码, 设备本身的安全性就很重要了,在 Google 的实现中 ,锁屏密码用于生成端到端加密的密钥,因此一个能够登录 Google 账户, 并且获知了锁屏 PIN 的人便能恢复出 passkey。根据文章的说法, 通过硬件保证了 PIN 只能尝试最多十次,但总体上, 无论是 Google 还是 Apple 的实现都依赖于一直在线的手机本身的安全性, 而 U2F 设备通常并不是连接在设备上的,因此我认为尽管对普通人来说 passkey 已经足够好,但对于需要持续提高电击电压的人群来说, 使用 密码 + U2F 会更安全一些。