通行密钥为什么安全 ── 图解读懂「不发送秘密的认证」机制

· · 通行密钥, WebAuthn, FIDO2, 安全, 认证, 防钓鱼, 信息系统

「某某大型服务的密码又泄露了」这样的新闻,如今已经没有人会感到惊讶。即便每年都开展钓鱼演练,上钩的人也从未归零。「密码不要重复使用、要设置得更长、定期更换……现在已经不用了」──说法也是几经反复。

近几年迅速普及的通行密钥(passkey),正是 Apple、Google、微软三家公司共同推动、作为这种局面之答案的认证方式。1 很多介绍都停留在「用指纹或人脸就能登录,很方便」这一层面,但本质并不在此。通行密钥真正的价值,在于把安全性的立足点从「人的注意力」转移到了「协议的结构」上。

  • 密码之所以泄露是因为用户不小心,所以要加强教育 → 人终究会犯错
  • 训练用户识破假网站 → 总能做出让人识别不出的假网站
  • 而通行密钥则是 → 压根就没有需要发送的秘密,在假网站上签名根本无法成立

本文将从「密码究竟坏在哪里」出发,用图解来把握通行密钥为什么安全。在此基础上,正面回答「会同步的通行密钥真的安全吗」「难道没有弱点吗」这些理所当然的疑问,最后整理在 Web 应用或 Windows 环境中导入时的实务要点。

1. 先说结论

通行密钥之所以安全,可以归纳为以下三点。

  1. 服务器上不存在秘密。服务器保存的只有公钥,这是即使泄露也无法被恶意利用的信息。就算数据库整体外泄,攻击者也带不走能够用来冒充的材料。2
  2. 秘密不会在网络上传输。登录时发送的,只是针对当场生成的随机数(挑战值)所作的签名。私钥完全不会从设备的认证器中流出,因此无论在传输路径的哪个环节窃听或中继,都无法获取秘密。2
  3. 在假网站上签名无法成立。通行密钥与网站的域名绑定,浏览器会强制核对域名。即使用户被假网站骗过,真正网站专用的通行密钥本就不会出现在候选之中;就算中继了签名,也会在验证环节被拒绝。3

这三点并非各自独立的巧思,而是全部源自同一个设计转变——从「共享并发送秘密」的认证,转向「用签名证明自己持有秘密」的认证——所导出的结果。下面依次来看。

术语之间的关系 ── 通行密钥・WebAuthn・FIDO2・CTAP

这个领域术语繁多,而且不同文章所指的范围也不尽相同,所以先把它们之间的关系理清楚。通行密钥并非一种新协议,而是给既有规格的组合起的一个「称呼」21

术语 正式名称 指的是什么
WebAuthn Web Authentication API(W3C 推荐标准) 浏览器与网站之间的规范。通过 navigator.credentials 请求创建密钥对及签名的 API
CTAP Client to Authenticator Protocol(FIDO 联盟) 浏览器与外接认证器之间的规范。经由 USB・NFC・蓝牙与安全密钥或手机通信的部分
FIDO2 上述两者合并而成的框架总称。FIDO2 = WebAuthn + CTAP
通行密钥(passkey) 在 FIDO2 凭据中,能够替代密码单独完成登录的一类(可发现凭据)的称呼

表1:通行密钥是建立在 FIDO2 这一基础之上的称呼,并不是规格名称

也就是说,所谓「支持通行密钥」,换成实现层面的说法就是「实现 WebAuthn」。CTAP 是在使用外接认证器时由浏览器和操作系统负责处理的一层,开发 Web 应用的一方不会直接接触到它。

2. 密码认证究竟坏在哪里

理解通行密钥安全性的捷径,是按「位置」来把握密码的弱点。在密码认证中,秘密本身在每次认证时都会走遍全部区间

服务器浏览器用户服务器浏览器用户在脑海中保存秘密(密码)【弱点①】可被猜测・被重复使用【弱点②】在假网站上同样能够输入(仅凭外观无法区分)【弱点③】秘密在传输路径上流动虽有 TLS 保护,但在终端会还原为明文【弱点④】所有用户的秘密(哈希值)都汇集于此一旦泄露就会成为离线暴力破解的目标输入密码直接发送密码本身与已保存的哈希值进行比对

图1:在密码认证中,秘密本身存在于所有区间

从攻击者的角度看,这是一种靶子多、容易命中的结构。

  • 弱点①(用户):强度仅限于人能记住的程度,并且会在多个网站上重复使用。一处泄露就会波及所有账户(撞库攻击)。
  • 弱点②(输入的瞬间):只要准备一个与真网站难以区分的假网站,用户就会主动把秘密交出来(钓鱼攻击)。
  • 弱点③(传输路径):由于有 TLS,直接窃听传输路径本身很困难,但一旦被插入一个「外观正规的中继点」,防护就形同虚设(即后文所述的 AiTM)。
  • 弱点④(服务器):即便以哈希形式保存,一旦数据库外泄,也能被离线暴力破解。强度较弱的密码会依次被破解。

「那么加上一次性验证码(短信或 TOTP)不就行了吗」——这就是传统的多因素认证,但它同样没有摆脱发送共享秘密的结构。TOTP 是服务器与认证 App 共享同一个种子(秘密),而生成出来的 6 位数验证码,用户终归还是能够输入到假网站里去。实际上,假网站将请求实时中继给真服务器的AiTM(Adversary-in-the-Middle,中间人)型钓鱼攻击,正是把「密码+一次性验证码」这一整套原样转发出去从而得手的。CISA(美国网络安全与基础设施安全局)将「具有抗钓鱼能力的 MFA」仅列举为 FIDO/WebAuthn 方式,以及智能卡(PIV/CAC)等基于 PKI 的认证这两种,并且把 FIDO 定位为其中的黄金标准,原因正在于此。4

也就是说,问题并不在于密码的「强度」,而在于「共享秘密、并在每次认证时都发送」这一结构本身

3. 通行密钥的真面目 ── 不发送秘密,只证明自己持有秘密

通行密钥是建立在 W3C 的WebAuthn与 FIDO 联盟的CTAP这两项标准(合称 FIDO2)之上、基于公钥加密的凭据。21 听起来似乎很复杂,但结构其实很单纯。

服务器用户的设备在本地进行核对数学上成对-制作签名的一方公钥即使泄露也无法被恶意利用「仅用于验证」的信息认证器——保险柜Windows Hello / Face ID /Android 屏幕锁 / 安全密钥私钥绝不会从这里流出指纹・人脸・PIN= 仅用于打开保险柜的门同样不会流出

图2:通行密钥的实体是按网站生成的密钥对。私钥一侧不会离开设备,服务器只持有用于验证的公钥

  • 私钥是能够生成签名的那一侧的密钥,保存在设备内的认证器(Windows Hello、iPhone 的 Face ID/Touch ID、Android 的屏幕锁,或是 YubiKey 之类的安全密钥)中,不会流出。
  • 公钥是只能用来验证签名的那一侧的密钥,会被交给服务器保管。从公钥反推出私钥在计算量上是不可能的,因此这是即使泄露也无妨的信息。
  • 指纹、人脸等生物特征信息,仅用于在本地打开保险柜的门,同样不会离开设备。生物特征信息不会被发送到服务器。1

注册:只交出公钥

这是在网站上注册通行密钥时的流程。

认证器浏览器服务器(example.com)认证器浏览器服务器(example.com)服务器收到的只是「即使泄露也无法被恶意利用的信息」注册请求(随机挑战值 + 网站信息)请为这个网站(example.com)生成密钥通过指纹・面容・PIN 进行本人验证(本地)生成新的密钥对私钥保存在内部公钥 + credential ID(密钥的标签)发送公钥 + credential ID作为该账户的公钥保存

图3:注册时在网络上传输、并保存在服务器上的只有公钥

重要的是,此时生成的密钥对会与网站的域名(RP ID)绑定在一起。为 example.com 生成的通行密钥,只能在 example.com 这个网站上使用(由于 RP ID 是以域名为单位的,因此可以从 login.example.com 这类同一域名下的子域名页面使用,但无法从毫不相关的域名使用)。这种绑定关系,正是后文所述抗钓鱼能力的基础。3

此外,密钥对每次都会针对每个网站重新生成。网站 A 与网站 B 的通行密钥在数学上互不相关,因此「重复使用」这个概念本身根本不存在,也无法被用作在不同网站之间比对用户身份的材料。

认证:返回一次性的签名

这是登录时的流程,请与密码认证(图1)对照来看。

认证器浏览器服务器(example.com)认证器浏览器服务器(example.com)在传输路径上流动的只是一次性的签名即使被窃取,也无法用于下一次的挑战登录请求(一次性随机挑战值)请求为 example.com 生成签名通过指纹・面容・PIN 进行本人验证(本地)用私钥生成签名将挑战值 + 来源(origin) + RP ID 哈希写入签名签名(并非私钥本身)发送签名用保存的公钥验证签名同时核对挑战值・来源・RP ID

图4:认证时秘密同样不会移动。流动的只是「当场使用一次的证明文件」

服务器每次都会出一道新的随机数(挑战值)题目,认证器则针对「该挑战值 + 浏览器当前所在的来源(origin) + RP ID 的哈希」生成签名。服务器用保存的公钥验证签名,确认挑战值确实是自己出的题目,来源与 RP ID 也确实属于自己的网站。5

作为这种设计的必然结果,开头所说三个理由中的两个已经成立。

  • 服务器上没有秘密:保存的只有公钥。即使泄露,攻击者也无法生成签名,不像密码的哈希那样可以「带回去破解」。
  • 秘密不会流动:即使窃取了传输路径上的签名,由于挑战值是一次性的,也无法重复利用(重放)。

剩下的一点——「在假网站上签名无法成立」——正是通行密钥最大的卖点。下面另立一节详细说明。

4. 钓鱼攻击为何在「结构上」无法成立

针对密码的钓鱼攻击之所以能够得逞,是因为能够把真正的秘密输入到假网站里。人在(尤其是疲惫的时候)很难区分 example.comexamp1e.com,而密码输入框在这两个网站上的表现却毫无二致。

而在通行密钥中,这项核对不是由人来完成,而是由浏览器机械地执行。按照 WebAuthn 的规范,只有在「当前显示页面来源的域名」与「通行密钥的 RP ID」相对应时,浏览器才能够调用认证器。3 下面用图来说明访问假网站的那一刻会发生什么。

真正的服务器(example.com)假网站(examp1e.com)向真网站转发的 AiTM 代理浏览器用户真正的服务器(example.com)假网站(examp1e.com)向真网站转发的 AiTM 代理浏览器用户即便通过某种方式生成了签名,由于签名中已写入 examp1e.com,在真正服务器的验证环节也必定会被拒绝访问外观极其相似的登录页面(在背后)启动真正的登录流程挑战值转发挑战值并请求签名当前来源是 examp1e.com无法把 example.com 专用的通行密钥列为候选不会生成签名(用户根本无从被骗)

图5:AiTM 型钓鱼攻击能够突破「密码+一次性验证码」,但对通行密钥而言,在签名阶段就无法成立

请注意,这里的防御是双重的。

  1. 不会出现在候选中:浏览器只会列出与当前来源相对应的 RP ID 所属的通行密钥。在假域名上,真网站专用的通行密钥根本不会作为选项出现,用户连「不小心用了」都做不到。
  2. 签名无法通过:签名的对象中包含了浏览器确认过的来源与 RP ID 的哈希。真正的服务器在验证时会核对这些信息,因此在其他来源生成的签名必定会被拒绝。5

针对密码的钓鱼防御,一直依赖于「用户仔细查看 URL」这种人的努力。而在通行密钥中,用户压根就不需要识破假网站。这正是「抗钓鱼(phishing-resistant)」一词的准确含义,也是 CISA 与 NIST(美国国家标准与技术研究院)对 FIDO/WebAuthn 方式给予特殊待遇的原因。46

下面按攻击手法,把到目前为止的内容整理成表格。

攻击 密码 密码+TOTP 通行密钥
猜测・暴力破解 ✗ 脆弱 △ 验证码能挡住,但原始密码依然脆弱 ○ 不存在可供猜测的对象
重复使用(撞库攻击) ✗ 一处泄露波及全部 △ 从未启用验证码的网站开始被攻破 ○ 每个网站的密钥相互独立
服务器数据库泄露 ✗ 哈希值可离线暴力破解 ✗ TOTP 的种子(共享秘密)也会一并泄露 ○ 只有公钥
传统钓鱼攻击(在假网站上诱导输入) ✗ 会被输入进去 ✗ 验证码也会被输入进去 ○ 不会出现在候选中,签名也无法通过
AiTM(实时中继) ✗ 原样被转发出去 ✗ 连同验证码一起被转发出去 ○ 因来源核对而无法生成有效签名
重放(通信的重复利用) ✗ 同一密码可反复多次生效 △ 在本人使用之前被截获的验证码依然有效(若实现正确,已使用过的验证码会被拒绝再次接受) ○ 挑战值每次都是一次性的

表2:按攻击手法划分的抗性对比。通行密钥一栏中的「○」无一例外都源于结构本身,而非依赖运维或注意力

5. 「会同步的通行密钥」安全吗

读到这里,自然会产生这样的疑问:「不是说私钥不会离开设备吗,那为什么在 iPhone 上创建的通行密钥在 iPad 上也能用?」──这是个好问题,答案是「通行密钥有两种」。

先把结论做成速查表放在前面。请把接下来这一节和下一节,当作是在解释表中每一行为什么会是这样来阅读。

视角 同步型通行密钥 设备绑定型通行密钥
代表示例 iCloud 钥匙串、Google 密码管理器、1Password 等密码管理器 安全密钥(YubiKey 等)、Windows Hello、Microsoft Authenticator 内的通行密钥
私钥的保管位置 平台的凭据保险库。以端到端加密的形式在同一账户的各设备之间复制 认证器的硬件内部。不会流出 TPM 或安全元件之外
丢失・更换设备时 只要登录同一个 Apple ID/Google 账户,即可在新设备上恢复 该认证器上的通行密钥会丢失。前提是预先注册多个备用认证器
单点故障 平台的云账户 物理设备本身
是否适合企业管理 由于密钥进入个人的云账户,组织一方难以掌握其所在或统一吊销。适合 BYOD 或小规模场景 管理员可以分发・吊销,密钥所在位置明确。适合规程严格的环境
对 NIST AAL 的符合情况 满足要求即可达到 AAL2。由于私钥可导出,无法用于 AAL36 由硬件保护、密钥无法取出的认证器,也可能满足 AAL3 所要求的条件6

表3:同步型与设备绑定型速查表。选择哪一种,取决于更看重「抗丢失能力」还是「可管理密钥所在位置」

设备绑定型通行密钥安全密钥-如 YubiKey 等 /Windows Hello /Microsoft Authenticator-Entra ID私钥不会从该硬件中物理性地流出-由 TPM 等保护优点-密钥所在位置单一明确注意-为应对丢失必须注册多个同步型通行密钥-面向消费者的默认选项iCloud 钥匙串 /Google 密码管理器 /1Password 等密码管理器在同一账户的设备之间以端到端加密方式同步服务商也无法读取内容优点-更换设备・丢失时依然可靠注意-需要加强云账户自身的防护

图6:同步型与设备绑定型。两者在「私钥不发送给服务器」这一点上相同,只是防护的重心不同

同步型通行密钥,是指 iCloud 钥匙串或 Google 密码管理器把私钥在同一账户的各设备之间进行同步的那种类型。这里重要的是,同步过程采用了端到端加密。Apple 与 Google 都明确表示,通行密钥会先在设备上加密再进行同步,就连服务商自己也无法读取其中的内容。78 也就是说,「私钥不会离开设备」这条原则被更精确地放宽为「私钥不会以明文形式离开设备」,作为交换,得到了对更换设备或丢失的抗性。

这种放宽会如何改变威胁模型,有必要明确说清楚。需要防护的对象,从「每个网站的服务器」集中到了「单一的云账户」。对各网站的数据库泄露和钓鱼攻击依然保持很强的抵抗力,而这一次,Apple ID/Google 账户本身被劫持则成为了新的单点故障。正因如此,对存放通行密钥的平台账户施加最强的保护(强密码锁屏、梳理好找回手段、条件允许的话再配上物理安全密钥)是一个大前提。NIST 也在 2024 年 4 月发布了NIST SP 800-63B 的补充文件(Supplement 1: Incorporating Syncable Authenticators Into NIST SP 800-63B),正式把这种同步型通行密钥(syncable authenticator)在满足条件的情况下,定位为可以达到政府标准中的AAL2(Authenticator Assurance Level 2,认证器保证级别 2)。不过,由于私钥存在被导出的可能性,要求硬件隔离环境的 AAL3 规定不得使用同步型认证器。6

设备绑定型通行密钥,是私钥不会离开硬件的类型。以 YubiKey 之类的安全密钥为典型代表,面向企业场景时,Microsoft Entra ID 的通行密钥(在 Microsoft Authenticator 内创建的那种)同样属于设备绑定型。9 Windows 的 Windows Hello 也是一样,只要有 TPM,就会把私钥保护在 TPM 之下。这种「不让密钥流出硬件保险柜」的机制本身,与TPM 一文中详细讲解过的是同一套基础。

另外,或许你曾对「用手机的通行密钥登录 PC 浏览器」时被要求扫描二维码这件事感到不解。那并不只是单纯的画面跳转,而是一种通过蓝牙确认手机与 PC 物理上处于同一位置的混合方式(FIDO 的跨设备认证)。它借助这种近距离确认,堵死了远程攻击者试图通过二维码诱使他人替自己批准登录 PC 的攻击手法。1

6. 并非银弹 ── 弱点不是「消失」,而是「转移」

到这里为止,一直在说明通行密钥的强大之处,但坦诚地说,通行密钥并不能消灭攻击,而是一种把攻击者赶往更薄弱之处的技术。当认证这道大门变得坚固之后,攻击者会转向何处,下面用图来说明。

攻击者认证本身挑战值签名【坚固】账户找回流程谎称『通行密钥丢失了』诱导通过短信或邮件重新设置进而注册攻击者自己的通行密钥并存的后备手段如果密码・短信登录依然保留,那里就是最薄弱的环节云账户若为同步型,Apple ID /Google 账户就是单点故障会话只要窃取登录后的 Cookie与认证方式无关

图7:当大门(认证)变得坚固后,攻击会转向找回流程・并存手段・云账户・会话

实务中需要掌握的残余风险有四个。

  1. 并存的后备手段会成为最薄弱的环节。如果只是让通行密钥「也」能使用,而密码或短信登录依然保留,攻击者只需转而使用那些手段即可。从账户整体来看,抗钓鱼能力会被最弱的那种登录方式的水平所限制。导入的重点并不在于新增通行密钥,而在于有计划地缩减・废止后备手段。
  2. 找回流程会成为新的攻击面。这是一种谎称「设备丢了」,从而通过支持窗口或邮件走上重新设置的流程,进而注册攻击者自己的通行密钥的手法。实际上,绕过坚固的认证、去欺骗帮助台的社会工程学手段,已经成为大规模入侵事件的惯用套路。认证被加固了多少,找回流程中本人验证该如何设计,就会被追问多少。
  3. 在同步型中,云账户是单点故障。正如前一节所述。既需要加强存放通行密钥的账户的防护,在组织中使用时也需要就「允许同步到哪个平台」制定方针。
  4. 无法防止会话窃取。通行密钥所保护的只是登录那一瞬间,一旦登录后的会话 Cookie 被恶意软件或 XSS 窃取,与所用的认证方式便毫无关系。令牌的有效期限管理、绑定、设备健全性管理,这些属于另一层面的工作依然存在。

以上并不是说「还是别用通行密钥了」,而是一个理所当然的道理——即便把大门的锁换成最新款,窗户要不要上锁是另一回事。反而正因为弱点所在变得明确,才更能把防御资源集中投入到找回流程与会话管理上。

7. 实务导入 ── WebAuthn API 与 Windows 环境

最后,从导入方的视角来把握要点。

为自家 Web 服务加入通行密钥登录

浏览器一侧只需用到 WebAuthn API 的两个函数:注册调用 navigator.credentials.create(),认证调用 navigator.credentials.get()

// 注册(浏览器端)
const credential = await navigator.credentials.create({
  publicKey: {
    challenge: challengeFromServer,   // 服务器生成的一次性随机数
    rp: { id: "example.com", name: "Example" },
    user: { id: userIdBytes, name: "taro@example.com", displayName: "太郎" },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }],  // ES256
    authenticatorSelection: {
      residentKey: "required",        // 设为可发现凭据(=通行密钥)
      userVerification: "required",   // 强制要求通过生物识别/PIN进行本人验证
    },
  },
});
// 公钥从 credential.response 中获取,credential ID 则从顶层的
// credential.id / credential.rawId 中获取。注册响应也应像认证时
// 一样,先在服务器端验证挑战值・来源・RP ID,然后再保存

主要参数的含义如下。

参数 作用 实现时的注意事项
challenge 服务器每次生成的一次性随机数 使用无法被推测的密码学随机数。服务器端需验证「确实是自己签发且尚未使用过的」之后再消费
rp.id 凭据所绑定的域名(RP ID) 省略时会取调用方来源(origin)的有效域名。只能在可注册域名的范围内指定,例如从 login.example.com 指定为 example.com
user.id 服务器内部的用户标识符(user handle) 64 字节以下的不透明值。不要直接放入邮箱地址或用户名等可识别个人的信息2
user.name / user.displayName 显示在认证器或浏览器界面上、供用户选择账户的字符串 仅用于显示。服务器不能凭此值来信任并确定账户
pubKeyCredParams 按优先顺序列出可接受的公钥算法 -7(ES256)外,一并列出 -257(RS256)可以扩大能够接受的认证器范围
authenticatorSelection 对认证器提出的要求 设为 residentKey: "required" 即成为通行密钥(可发现凭据),设为 userVerification: "required" 则强制要求通过生物识别・PIN 进行本人验证

表4:navigator.credentials.create() 的主要参数

验证环境注意事项:由于 WebAuthn API 只在安全上下文中才会被公开,因此以裸 http:// 提供的页面中,调用 navigator.credentials 会失败。例外是 http://localhost(以及 127.0.0.1),它们会被当作可信来源处理,因此在开发机上即便不做 HTTPS 化也可以直接试用。不过 RP ID 必须是来源的有效域名(或其父域名),所以在 localhost 上创建的通行密钥无法在生产域名上使用。即便手边没有认证器,只要在 Chrome 开发者工具的「WebAuthn」标签页中启用虚拟认证器,也能把从注册到认证的整个流程跑一遍。

// 认证(浏览器端)
const assertion = await navigator.credentials.get({
  publicKey: {
    challenge: challengeFromServer,
    rpId: "example.com",
    userVerification: "required",
  },
  // 将通行密钥作为登录框的自动填充候选项呈现。请预先通过
  // PublicKeyCredential.isConditionalMediationAvailable() 确认是否支持,
  // 在不支持的浏览器中回退为不带 mediation 参数的普通调用
  mediation: "conditional",
  // (需要在目标 <input> 上指定 autocomplete="username webauthn")
});
// 在服务器端验证 assertion.response 中的签名

核心工作在于服务器端的验证。以下几项是必须做到的最低限度。5

  • 核对挑战值:是否是自己签发的、尚未使用过的挑战值;是否做到了一次性使用(防重放)。此外,还要在签发时与浏览器会话(登录尝试)绑定保存,只允许来自同一会话的响应消费它。如果这里做得不够严格,就会给攻击者留下可乘之机:让受害者的浏览器帮忙送出针对攻击者自己那份挑战值的签名,从而使受害者登录到攻击者的账户中(登录 CSRF)。
  • 核对来源clientDataJSON 中的 origin 是否是自家网站的正规来源(这是抗钓鱼的关键)。
  • 核对 RP ID 哈希authenticatorData 中的 rpIdHash 是否与自家网站 RP ID 的 SHA-256 一致。
  • 确认操作类型与标志位clientDataJSON 中的 type,在认证时是否为 webauthn.get,注册时是否为 webauthn.createauthenticatorData 中的 UP(用户在场)标志是否已置位;如果要求了用户验证(UV),UV 标志是否也已置位。
  • 验证签名:能否用注册时保存的公钥正确验证签名。
  • 与账户的绑定:用提交上来的 credential ID(以及 userHandle)在自己的数据库中查询,并向该凭据的所有者签发会话。如果无条件信任另外输入的用户名,就会出现一个漏洞——用正确的签名却把用户登录成了别人。
  • 保存并比较签名计数器:按凭据分别保存 authenticatorData 中的 signCount,并确认下一次的值比上一次更大。若小于或等于上一次的值(含相同的情况),则应视为认证器被复制(克隆)的迹象。不过由于许多实现中同步型通行密钥总是返回 0,因此仅当两次都是 0 时才作为例外予以放行。

自己手写这套验证逻辑很容易埋下事故隐患,请使用经过实践检验的库(.NET 用 fido2-net-lib,Node.js 用 SimpleWebAuthn 等)。把规范中的细节(CBOR 解析、算法协商、挑战值管理)交给库去处理,自己则把精力集中在挑战值的保存与失效、多个通行密钥的管理界面、找回流程的设计上,这才是正确的力量分配方式。

Windows 环境・企业内部系统的情况

对于本站的主要读者──「负责 Windows 业务系统」的这一立场而言,只需掌握以下三点就足够了。

  • Windows 客户端已经支持。Windows 11 支持以 Windows Hello 作为认证器来创建・使用・管理通行密钥(设置 > 账户 > 通行密钥),只要有 TPM,私钥就会得到硬件保护。10 通过浏览器(Edge/Chrome)使用的 WebAuthn,在 Windows 10 上也能运行。
  • 在 Entra ID 环境中启用「通行密钥=FIDO2 认证方式」。Microsoft Entra ID 支持安全密钥以及 Microsoft Authenticator App 内的通行密钥(设备绑定型),只要在条件访问的认证强度中要求「抗钓鱼 MFA」,就能把对目标资源的访问限定为通行密钥等方式。9 从 NTLM 与密码有效期策略的世界迁移过来不可能一蹴而就,因此常见的做法是,在与NTLM 与 Kerberos 一文中所讨论的认证基础设施盘点并行推进的同时,先从管理员账户开始强制启用抗钓鱼 MFA。
  • 企业内部的 Web 应用同样能获得同样的收益,但前提是要有 HTTPS。由于 WebAuthn API 只能在安全上下文中运行,因此即便是内网应用(除开发时的 localhost 外),也必须优先完成 HTTPS 化,以及整理出可以用作 RP ID 的内部域名。只要做好这一步,RP ID 对内部域名同样有效。就「告别贴在显示器上的密码便签」这层意义而言,企业内部往往比对外服务更快见到效果,这种情况并不罕见。

8. 总结

  • 密码的弱点不在于强度,而在于「共享秘密、并在每次认证时都发送」这一结构。由于秘密同时存在于用户、输入框、传输路径、服务器等所有环节,攻击面因此很多。即便加上一次性验证码,面对 AiTM 型钓鱼攻击,仍会因被中继而落败。
  • 通行密钥是按网站各自生成的公钥加密密钥对,交给服务器的只是即使泄露也无法被恶意利用的公钥,登录时发送的也只是针对一次性挑战值的签名。服务器上没有秘密,传输路径上也不会流动秘密
  • 由于签名中写入了浏览器确认过的来源与 RP ID,假网站上不会出现真网站专用的通行密钥,即便被中继也会在验证环节被拒绝。用户无需识破假网站,这正是「抗钓鱼」的真面目,防御的立足点已经从人的注意力转移到了协议的结构上。
  • 同步型通行密钥通过端到端加密进行同步,对更换设备和丢失有较强的抵抗力。作为交换,需要防护的对象集中到了云账户上,因此 Apple ID/Google 账户自身的防护便成为大前提。企业也可以选择设备绑定型(安全密钥、Entra ID 的 Authenticator 通行密钥)。
  • 通行密钥并不能消除攻击,只是把攻击赶向更薄弱之处。并存的密码、账户找回流程、会话窃取,都是依然存在的攻击面,导入工作的重点在于有计划地缩减后备手段以及加强找回流程。
  • 实现方式是 WebAuthn API 的 create / get 这两个函数,加上服务器端验证。验证不要自己造轮子,交给经过实践检验的库,把精力分配在挑战值管理、多通行密钥的界面、找回设计上。

相关文章

相关咨询领域

合同会社小村软件承接的委托开发业务,涵盖为企业内部 Web 系统实现通行密钥登录(WebAuthn)提供支持、设计 Entra ID 环境下的抗钓鱼 MFA 部署方案,以及将认证功能嵌入 WinForms/WPF 等 Windows 业务应用等内容。

  1. FIDO 联盟,Passkeys(通行密钥)以及How FIDO Works。关于通行密钥作为 FIDO 凭据用于取代密码,生物特征信息不会从设备发送出去、只用于本地核对,2022 年 5 月 Apple・Google・微软共同宣布将扩大对基于 FIDO 标准的无密码方式的支持,以及跨设备(cross-device)使用时会采用结合二维码与蓝牙近距离确认的混合方式。  2 3 4 5

  2. W3C,Web Authentication: An API for accessing Public Key Credentials Level 2(W3C 推荐标准)。关于 WebAuthn 是用于创建・使用基于公钥加密的凭据的 API,凭据的私钥保存在认证器中,服务器(Relying Party)只会登记公钥与 credential ID,认证是通过对服务器发出的挑战值进行签名(断言)来完成的,以及凭据的作用域与保护方面的设计目标。同时,正文中也参照了该规范中关于 API 仅在安全上下文中公开、RP ID 省略时取调用方来源的有效域名、user handle(user.id)是最长 64 字节的不透明值且不应包含用户名或邮箱地址等可识别个人的信息(§14.6.1 User Handle Contents)等内容。  2 3 4 5

  3. W3C,Web Authentication Level 2 — §5.1.3 Create / RP ID validation, §13.4.9 Regarding phishing。关于公钥凭据的作用域被限定在 RP ID(Relying Party 标识符=域名)之内,浏览器(客户端)会核对调用方来源的可注册域名与 RP ID 是否对应,若不对应则拒绝创建・使用凭据,由此使得伪造来源无法访问其他网站专用的凭据,从而让 WebAuthn 具备包括中间人攻击在内的抗钓鱼能力。  2 3

  4. CISA,Implementing Phishing-Resistant MFA(2022 年 10 月的说明文件)。关于使用短信、语音、推送通知、OTP 的 MFA 对钓鱼攻击、AiTM(中继)攻击、MFA 疲劳攻击均较为脆弱,抗钓鱼方式列举了 FIDO/WebAuthn 认证与基于 PKI 的认证(智能卡等)两种,其中 FIDO/WebAuthn 认证被定位为黄金标准,以及组织应首先从高风险账户开始迁移到抗钓鱼 MFA。  2

  5. W3C,Web Authentication Level 2 — §7.2 Verifying an Authentication Assertion。关于该规范中规定的服务器端验证步骤,包括对 clientDataJSON 的 type・challenge(与自己签发的值一致)・origin 进行验证,验证 authenticatorData 中的 rpIdHash 是否与期望的 RP ID 的 SHA-256 哈希一致,确认 User Present / User Verified 标志,以及用保存的公钥验证签名。  2 3

  6. NIST,Incorporating Syncable Authenticators Into NIST SP 800-63B(2024 年 4 月的补遗,已并入 SP 800-63B 第 4 版)。关于可同步认证器(同步型通行密钥)的私钥,若以满足要求的形式保存・复制到同步结构中,即可满足 AAL2;另一方面,由于 AAL3 的加密认证器要求硬件保护・隔离的环境,因此私钥可导出的同步型认证器不得用于 AAL3;以及像 WebAuthn 这样进行来源验证的方式,被归类为具备验证者冒充抗性(抗钓鱼能力)。原文 PDF 见NIST SP 800-63B Supplement 1。  2 3 4

  7. Apple 支持,关于通行密钥的安全性。关于通行密钥通过 iCloud 钥匙串进行同步,iCloud 钥匙串采用端到端加密、连 Apple 自身也无法读取,同步受用户设备上的密钥保护,并提供了带有速率限制的托管(escrow)恢复机制。 

  8. Google,Google 密码管理器中通行密钥的安全性。关于通行密钥的私钥会在设备上加密后再同步,通过端到端加密使 Google 自身也无法访问私钥的内容,恢复时需要基于设备锁屏等方式的保护。 

  9. Microsoft Learn,在 Microsoft Entra ID 中启用 FIDO2 认证(通行密钥)。关于 Entra ID 支持通过 FIDO2 安全密钥以及 Microsoft Authenticator 的通行密钥(设备绑定)实现具备抗钓鱼能力的无密码认证,可以在认证方法策略中启用,并通过条件访问的认证强度(抗钓鱼 MFA)提出要求。  2

  10. Microsoft Learn,Windows 对通行密钥的支持。关于 Windows 11 支持使用 Windows Hello 创建・使用通行密钥,可以从设置 > 账户 > 通行密钥中管理已保存的通行密钥,在可使用 TPM 的环境中 Windows Hello 的凭据会受到硬件保护,以及可以通过二维码使用移动设备上的通行密钥。 

共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。

与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。

常见问题

汇总了咨询这一主题时常见的问题。

通行密钥与密码在根本上有什么不同?
密码的机制是「用户与服务器共享同一个秘密,并在每次登录时发送这个秘密」。由于秘密存在于用户的脑海、输入框、通信路径、服务器数据库等所有地方,因此所有这些环节都会成为攻击目标。通行密钥使用的是公钥加密的密钥对,私钥不会被发送到服务器。在设备绑定型中,私钥完全不会从认证器中流出;即便在同步型中,也只会以端到端加密的形式流出到外部。服务器保存的只是公钥这种「即使泄露也无法被恶意利用的信息」,登录时发送的也只是针对当场一次性挑战值的签名。也就是说,密码的弱点所在——「共享的秘密」本身——根本不存在。此外,由于密钥对是按每个网站分别生成的,因此「重复使用」这个概念也无从谈起。
生物特征信息(指纹・人脸)会被发送到服务器吗?
不会。指纹或人脸数据只是在设备内部用于「打开装有私钥的保险柜」的本地核对手段,按照 FIDO 的设计,生物特征信息不会被发送到设备之外。服务器收到的,只是一个标记着「已完成用户本人验证(用户检验)」的签名,不仅不包含指纹本身,连其特征值也完全不包含。在无法使用生物识别的场景下可以用 PIN 代替,这个 PIN 与 Windows Hello 的 PIN 一样,也只在设备本地进行核对,不会在网络上传输,这一点与密码有着决定性的不同。
为什么通行密钥对钓鱼攻击有很强的抵抗力?
因为从机制上来说,用户压根就不需要识破假网站。通行密钥与网站的域名(RP ID)绑定在一起生成,浏览器只会把与「当前显示网站的域名」相对应的通行密钥列为候选。即便访问了外观与真网站极其相似的假域名,真网站专用的通行密钥也不会出现在选项中,用户根本无从被骗。此外,由于签名中写入了浏览器确认过的来源与 RP ID 的哈希,即便中继了签名,也会在真正服务器一侧的验证环节被拒绝。像密码或短信验证码那样「把真正的凭据输入到假网站里」这种事故,在结构上根本无法发生,这正是它与依赖训练或提醒注意的对策之间根本性的区别。
手机丢了会导致无法登录账户吗?
如果是同步型的通行密钥(保存在 iCloud 钥匙串或 Google 密码管理器中的那种),那么只要在登录了同一个 Apple ID/Google 账户的新设备上,就可以恢复。不过,恢复端到端加密的保管库,除了账户密码之外,还需要输入此前设备的锁屏密码等额外的本人验证,因此如果连这些找回手段也一并丢失,就可能无法恢复。不要把一切都只寄托在一台手机上,这种心态很重要。设备绑定型(安全密钥、Windows Hello 等)与设备命运与共,因此对于重要账户,惯常做法是提前注册多个通行密钥。许多服务都支持在一个账户上注册多个通行密钥。需要注意的是,丢失时的失效处理流程会因类型而异:同步型由于各设备上的副本都是同一份凭据,因此首先要在平台账户一侧删除丢失的设备或进行远程擦除,使设备上的副本无法再使用(在服务一侧的账户设置中删除该通行密钥,会一次性使所有设备上的副本失效)。而对于设备绑定型,只要在服务一侧删除该认证器的通行密钥,就只会使丢失的那把密钥失效。在组织中使用时,重要的是把「用户能够自行恢复的双重化机制」与「丢失时管理员能够予以吊销的流程」一并设计好。
通行密钥也有弱点吗?
有。不过更准确的说法是,弱点所在的位置发生了变化。由于认证本身借助公钥加密变得更加牢固,攻击者就会转而瞄准更薄弱的周边地带。具体来说包括:如果密码、短信等传统手段依然并存,那里就会作为最薄弱的环节残留下来;利用账户找回流程、诱导注册攻击者自己的通行密钥的手法;在同步型中,云账户本身被劫持会成为新的单点故障。此外,窃取登录后会话 Cookie 的攻击并不能被通行密钥防住,也就是说,与之无关的威胁并不会因此消失。导入时不能只满足于「加上通行密钥」,还需要把找回流程的加固,以及有计划地缩减后备手段一并纳入设计之中。

作者简介

本文作者的个人简介页面。

Go Komura

小村软件有限公司 代表

以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表