Passkey通行密钥:为什么用指纹登录比密码更安全

Passkey 基于 WebAuthn/FIDO,用非对称加密让私钥不出设备、并与域名绑定,从原理上防钓鱼。

Passkey通行密钥:为什么用指纹登录比密码更安全

你有没有算过自己记了多少个密码?又有多少次因为「忘记密码」而走找回流程?

密码这套用了几十年的登录方式,正在被一种更安全也更省心的机制取代——它叫 Passkey(通行密钥)。用指纹或面容一刷就登录,且从原理上就防钓鱼。

本文讲清它是什么、怎么工作、怎么落地。

密码为什么该退休

先说清问题。密码有三个老毛病:容易被猜/被撞库、容易在钓鱼网站被骗走、还要用户自己记。即便加了短信验证码,也挡不住实时钓鱼(攻击者把你输入的验证码即时转发到真网站)。

Passkey 换了个思路。它基于 WebAuthn / FIDO 标准,用的是「非对称加密」——注册时你的设备生成一对钥匙:私钥永远留在你的设备里(受指纹/面容/PIN 保护,绝不外传),公钥交给网站保存。登录时网站发来一个随机「挑战」,你的设备用私钥签名,网站用公钥验证。整个过程没有任何「秘密」在网络上传输。

为什么它天生防钓鱼

这是 Passkey 最关键的优势。每个 Passkey 都和一个具体的网站域名「绑定」。如果你被骗到一个仿冒域名,浏览器根本不会拿出对应的 Passkey——因为域名对不上。也就是说,就算你想上当,技术上也交不出凭证。

一个最小可运行的例子

在网页里,浏览器通过 navigator.credentials API 直接对接系统的生物识别。注册和登录各是一次调用:

// 1) 注册:创建一个 Passkey(options 由你的服务端生成)
const cred = await navigator.credentials.create({
  publicKey: {
    challenge: serverChallenge,          // 服务端下发的随机值
    rp: { name: "示例站点", id: "example.com" },
    user: { id: userId, name: "user@example.com", displayName: "小明" },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }], // ES256
    authenticatorSelection: { residentKey: "required", userVerification: "required" },
  },
});
// 把 cred 里的公钥等信息发回服务端保存

// 2) 登录:用已有 Passkey 签名挑战
const assertion = await navigator.credentials.get({
  publicKey: { challenge: serverChallenge, rpId: "example.com" },
});
// 把 assertion 发回服务端,用之前存的公钥验证签名

注意:客户端只负责「唤起系统验证 + 拿到签名」,真正的挑战生成签名验证必须在服务端完成,且 challenge 必须一次性、随机、有时效——这是安全的关键。

取舍与边界

  • 设备同步与找回:现代 Passkey 可通过平台账号(如系统钥匙串)在你的设备间同步,换手机不至于全丢;但仍要设计好账号恢复流程,避免用户彻底被锁在外面。
  • 跨生态:在不同厂商设备/浏览器之间使用时,通常靠「扫码 + 手机」的跨设备流程衔接,体验在持续改善。
  • 过渡期共存:多数网站会让 Passkey 与密码并存一段时间,逐步引导用户迁移,而不是一刀切。
  • 它保护的是「登录」:Passkey 解决身份验证,不替代授权、会话管理等其它安全环节。

Tips

  • 新系统做登录,优先支持 Passkey,把密码作为过渡兜底而非唯一选项。
  • 服务端务必保证 challenge 随机、一次性、有时效,验证逻辑放服务端。
  • 一定要设计好账号恢复路径(备用邮箱、多设备等),别让用户丢设备就丢账号。
  • 向用户解释「用指纹登录 = 更安全」,降低迁移心理门槛。
  • 记住 Passkey 的核心卖点:私钥不出设备 + 与域名绑定,从原理上防钓鱼。

KEEP READING