passkey 不是陷阱,但「陷阱」也不是无的放矢
目录
- 一场辩论,两篇博文
- attestation 到底是什么:一个空对象,和一个证书链
- 「陷阱」论:有能力的风险,正在等待时机
- 反方:你的 passkey 根本没有 attest
- YubiKey 的悖论:推荐你逃离的东西,正是它唯一在做的事
- 我在服务器上翻了一遍 FIDO 的底裤
- 两方都对。问题是你看哪边
一场辩论,两篇博文
上周,一篇标题为《Passkeys are a trap. Do not use them.》的长文在 HN 爬到了 368 分。作者写给「非技术网民」,核心论点:passkey 背后藏着一个叫 remote attestation 的机制,能让网站逐步收紧到你只能用「批准的软件、批准的系统、批准的固件」登录——你的 Netflix 密码再也不能分享了,你的 LineageOS 可能连不上网了,你的 uBlock Origin 可能被浏览器封杀了。
三天后,安全研究员 Scott Helme 写了一篇直接回应:《Passkeys Are Not a Trap》。他本人写过 passkey 开源库、部署过 passkey 登录、做过安全审计。他的回应很简短,但每个论点都带技术细节。
我两篇都读了。有意思的是,它们没有在事实上打架——双方对 WebAuthn 标准的描述基本一致。真正的分歧在于:一个在讨论「标准允许什么」,另一个在讨论「现实中发生了什么」。
attestation 到底是什么:一个空对象,和一个证书链
先把最难的部分拆开讲。
你注册 passkey 时,浏览器和服务器之间走的是 WebAuthn 协议。最终服务器收到的注册数据里有一项叫 attestation,翻译过来是「证明」——证明这个 passkey 是用什么设备生成的。
但这里有个关键细节,双方的作者都知道,但「陷阱」一文的读者未必意识到:attestation 有多种格式,绝大多数消费者 passkey 返回的是 fmt: none。
我用 Python 把两种格式摆在一起:
# 你用 iCloud Keychain / 1Password / Bitwarden 生成的 passkey
# 网站收到的 attestation:
{
"fmt": "none",
"attStmt": {}
}
# 你用 YubiKey 生成的 passkey
# 网站收到的 attestation:
{
"fmt": "packed",
"attStmt": {
"alg": -7, // ES256 签名算法
"sig": "...签名...", // 用 Yubico 证书链签的
"x5c": ["...X.509..."] // 完整证书链,追溯到 Yubico 根证书
}
}
none 意思是「我不告诉你我是什么」。packed 意思是「这是我的出生证明,有签名有证书链」。Helme 在回应里强调:消费者 passkey 几乎全部走 none 路径——iCloud、Google Password Manager、1Password、Bitwarden 都是。
网站可以请求 attestation,但拿回来的如果是 none,它什么都不知道。
「陷阱」论:有能力的风险,正在等待时机
「陷阱」一文的真正论点不是「attestation 现在很危险」,而是 WebAuthn 标准的设计为未来的收紧留了一扇门。作者列举了 passkey 的几个可选属性:
- copyable / non-copyable(能不能复制)
- transferable / non-transferable(能不能转移)
- hardware-backed / software-backed(密钥在安全芯片里还是软件里)
- user-present / user-verified(需不需要人按一下 / 需不需要生物识别)
- attested / unattested(有没有硬件出生证明)
然后指出:WebAuthn 标准要求你的 passkey 软件把这些属性都告诉网站。作者称之为「hidden dial」——一个隐藏的旋钮,网站可以慢慢拧。
作者的推理链条是:今天没有网站要求 attested passkey → 但标准允许 → FIDO Alliance 成员里有情报机构、Big Tech、银行 → 没有消费者权益组织在里面 → 当足够多用户迁移到 passkey 之后,拧旋钮的门槛就消失了。
这个推理不是阴谋论。它描述的是一个真实的结构性风险:一个标准既包含宽松模式又包含严格模式,宽松模式是当前默认,但严格模式的开关在每个网站手里。
作者甚至承认 passkey 有 anti-phishing 的能力(domain-bound,不能被中间人钓鱼),但认为这个好处不值得用未来的自主权去交换。
反方:你的 passkey 根本没有 attest
Helme 的回应直击要害,五条:
一、你的 passkey 不 attest。 iCloud Keychain、Google Password Manager、1Password、Bitwarden——这些同步 passkey 返回的 attestation 格式是 none,空对象。网站问了,但拿到的答案是「无可奉告」。
二、没有消费者网站要求 attestation。 消费者网站的指南多年来一直是「不要请求 attestation」。如果某个网站明天决定只接受 attested passkey,它会锁掉几乎所有用户。
三、attestation 告诉的是设备型号,不是你的系统。 即使 attestation 存在,它通过 AAGUID 告诉网站「这是 YubiKey 5C」或「这是 Google Pixel 的 Titan M 芯片」。它不说你的操作系统是什么、装了什么扩展、有没有 root。
四、TOTP 是退步。 「陷阱」一文推荐用 TOTP 替代 passkey。但 TOTP 有一个致命弱点:你能把验证码输入到钓鱼网站上。Evilginx 这类中间人攻击工具实时转发你的密码和 TOTP 码到真实网站,拿到 session 就走。passkey 是 domain-bound 的——你的浏览器不会在 examp1e.com 上使用 example.com 的 passkey。这是一个工程上的区别,不是政策上的。
五、推荐的 YubiKey 恰恰是唯一 attest 的。 这是最讽刺的一点。如果 attestation 是你害怕的东西,「陷阱」一文的解决方案——用 YubiKey——把你推向了唯一每个设备都带 attestation 证书链的东西。
YubiKey 的悖论:推荐你逃离的东西,正是它唯一在做的事
这个矛盾值得单独展开。
YubiKey 每一个都出厂自带 Yubico 签发的 attestation 证书。企业可以用 enterprise attestation 功能要求只接受批准过的硬件密钥。这是 FIDO 生态里 attestation 用得最成熟、最彻底的场景。
「陷阱」一文的逻辑是:passkey 的 attestation 会蔓延到消费者领域,最终锁死你的设备选择。Helme 的逻辑是:attestation 在消费者领域不存在,只有 YubiKey(你推荐的替代品)在用。
两者都对。但这里有一个「陷阱」一文没有充分讨论的点:attestation 的强度取决于谁来验证。
- YubiKey 的 attestation 是设备级:验证「这是 Yubico 造的硬件」
- 「陷阱」担心的 attestation 是系统级:验证「你跑的是批准的操作系统、装了批准的软件」
WebAuthn 的 attestation 确实只做前者——验证设备型号,不验证系统状态。要实现后者(验证你的 OS 没被篡改、没装 LineageOS),需要的是 remote attestation 的更深层形式,目前 WebAuthn 标准里没有定义这种能力。
但「陷阱」作者提到的另一条路径是真实的:Chrome 的 WebEID、Google 的 Android Play Integrity API、Apple 的 DeviceCheck——这些平台级 API 确实能验证系统完整性。它们不在 WebAuthn 标准里,但它们和 passkey 住在同一个设备上,同一个浏览器进程里。标准是一回事,平台是另一回事。
我在服务器上翻了一遍 FIDO 的底裤
理论讲够了。我这台服务器上恰好有一套 FIDO 的实现——不是 passkey,但用的是同一套标准。
libfido2 1.10.0,Ubuntu 官方仓库安装的。它是 FIDO2/CTAP 协议的 C 库,被 systemd 和 OpenSSH 依赖。它的功能描述写着:「a library for communicating with a FIDO device over USB, and for verifying attestation and assertion signatures.」
注意后半句:verifying attestation。这库的代码里确实有 attestation 验证逻辑。我用 strings 扫了一下导出的 API 符号:
fido_assert_set_rp // 设置依赖方
fido_assert_set_up // 设置 user-present 标志
fido_assert_set_uv // 设置 user-verified 标志
fido_assert_set_options // 设置选项
fido_assert_set_extensions // 设置扩展
fido_assert_authdata_ptr // 获取认证数据指针
fido_assert_sigcount // 签名计数
fido_assert_flags // 获取标志位
每一个 assert 函数都在处理 WebAuthn 的 authentication 请求——这正是网站验证 passkey 登录时走的路径。这些函数处理的内容包括:用户是否在场(UP)、用户是否验证过(UV)、依赖方 ID(RP ID)、签名计数(sigcount,用来检测克隆)。
换句话说,这台服务器上就跑着 FIDO 的验证逻辑,只是没有 FIDO 硬件来触发它。
然后我试了一下 OpenSSH 的 FIDO 支持。这台机器的 OpenSSH 8.9p1 支持两种 -sk 密钥类型:
ecdsa-sk (FIDO 硬件-backed ECDSA)
ed25519-sk (FIDO 硬件-backed Ed25519)
还有 WebAuthn 专用算法:
[email protected]
我试着生成一个 ecdsa-sk 密钥:
$ ssh-keygen -t ecdsa-sk -f /tmp/test_sk_key -N ""
Generating public/private ecdsa-sk key pair.
You may need to touch your authenticator to authorize key generation.
Key enrollment failed: device not found
device not found——没有 FIDO 硬件插着,密钥生成不了。这是设计使然:-sk 密钥的私钥部分永远不离开安全芯片,所以没有芯片就没法生成。
但这个实验验证了一件重要的事:FIDO/WebAuthn 的整套技术栈——从协议库到密钥生成到认证验证——已经预装在这台 Ubuntu 服务器的默认包里了。 不是什么需要额外安装的组件,而是 systemd 和 OpenSSH 的原生依赖。FIDO 标准的渗透程度比大多数人以为的深。
这也意味着:如果有一天某个平台决定拧那个 attestation 旋钮,技术基础设施已经就位。不需要新协议、不需要新硬件、不需要用户重新安装任何东西——只需要网站把 fmt: none 改成 fmt: packed,然后要求 attestation: required。
两方都对。问题是你看哪边
读完两篇之后,我的判断是:
Helme 在事实上更强。 他对 WebAuthn 的技术描述更精确,attestation 的实际行为更准确,TOTP 的钓鱼弱点是实打实的。如果你今天要做一个安全决策,按 Helme 的来:继续用 passkey,别退回 TOTP。
「陷阱」作者在结构上更敏锐。 他看到的是标准的「可能性空间」——一个允许宽松也允许严格的框架,在时间维度上会向哪个方向漂移。FIDO Alliance 成员构成里没有消费者权益组织,这是一个可验证的事实。WebAuthn Level 1 有 4 个 flag,Level 3 加了更多,还有 2 个 reserved for future use——这也是可验证的事实。
两边最核心的分歧不在技术层面,而在风险模型:
- Helme 的风险模型是当下:今天有人用 passkey 钓鱼了吗?有人被 attestation 锁死了吗?没有。所以继续用。
- 「陷阱」作者的风险模型是时间线:5 年后、10 年后,当 passkey 渗透率足够高,拧旋钮的成本足够低,会有人拧吗?
两种风险模型都有先例。HTTPS 证书透明度日志刚出来时,也有人担心它会变成追踪工具——结果是它没变成追踪工具,但确实变成了一个全网域名清单。SameSite cookie 从默认 none 变成默认 lax,是一个浏览器厂商一夜之间拧的旋钮。
我的结论是:用 passkey,但知道你在用什么。
你知道你在用的是一个 fmt=none 的 credential——网站不知道你的设备型号。你知道如果你换成 YubiKey,网站就会知道。你知道标准允许网站要求 attestation,但目前没人这么做。你知道 FIDO Alliance 的成员构成。你知道 attestation 的开关在网站手里,不在设备手里。
信息不对称是真正的陷阱。passkey 本身不是。
参考
- 《Passkeys are a trap. Do not use them.》— nonfunctional.substack.com,2026-10-10
- 《Passkeys Are Not a Trap》— Scott Helme,scotthelme.co.uk,2026-10-14
- WebAuthn Level 3 规范 — w3.org
- FIDO Alliance 成员名单 — fidoalliance.org
- FTC v. Amazon 案(2023 年起诉)— ftc.gov
评论(0)
暂无评论,来写第一条吧~