Move beyond passwords
Privacy & Security 进阶 20m

超越密码:走向无密码认证

Move beyond passwords

2021年6月10日

在 Apple 官方观看视频

一句话判断

苹果在 WWDC 2021 正式预告了 Passkeys(基于 FIDO2/WebAuthn 的无密码认证)—— 密码终将被设备级密钥替代,虽然完整实现在后续版本才落地,但这集 Session 是你理解苹果身份认证路线图的关键节点。

这场 Session 讲了什么

Session 系统讲解了苹果在身份认证领域的三个方向:密码管理的改进、多因素认证的简化、以及 Passkeys(通行密钥)的概念预览。

密码方面,iCloud Keychain 新增了内置的密码泄露检测(Security Recommendations),如果用户的密码出现在已知的数据泄露列表中,系统会主动提醒更换。Safari 的自动填充也做了改进,支持更复杂的表单场景。

多因素认证方面,结合前面 Session 10105 讲到的 iCloud Keychain TOTP 功能,登录流程中的二步验证可以全自动完成。

Passkeys 方面,这是苹果对 FIDO Alliance(FIDO 联盟)提出的无密码认证方案的实现。用户的认证密钥存储在设备 Secure Element 中,通过 Face ID/Touch ID 触发,不需要输入任何密码。密钥通过 iCloud Keychain 在设备间同步。

值得深挖的点

Passkeys 的技术架构。Passkeys 基于 WebAuthn(Web Authentication)标准,但和传统 WebAuthn 的关键区别在于:传统 WebAuthn 的密钥绑定在单个设备上(需要额外的安全密钥硬件),而 Passkeys 通过 iCloud Keychain 同步到用户的所有设备。这解决了”丢失设备 = 丢失所有凭据”的致命问题。密钥使用 Secure Element 存储,永远不会暴露给网站或 app。

向后兼容性策略。Passkeys 不是一步到位替代所有密码。在 iOS 15 中,Safari 会优先尝试 Passkey 认证,如果网站不支持,回退到密码自动填充。对于开发者,苹果建议同时支持 Passkey 和传统密码登录,渐进式迁移。WebAuthn API 的 JavaScript 接口在 Safari 15 中已经可用。

代码片段

WebAuthn 注册 Passkey(Web 端)

// 网站端:注册新的 Passkey
async function registerPasskey() {
    const challenge = new Uint8Array(32);
    crypto.getRandomValues(challenge);

    const credential = await navigator.credentials.create({
        publicKey: {
            challenge: challenge,
            rp: { name: "My App", id: "myapp.com" },
            user: {
                id: new Uint8Array(16),
                name: "user@example.com",
                displayName: "示例用户"
            },
            pubKeyCredParams: [
                { type: "public-key", alg: -7 },   // ES256
                { type: "public-key", alg: -257 }  // RS256
            ],
            authenticatorSelection: {
                authenticatorAttachment: "platform",
                userVerification: "required"
            }
        }
    });

    // 将 credential 发送到服务端存储
    await fetch('/api/register-passkey', {
        method: 'POST',
        body: JSON.stringify({
            id: credential.id,
            rawId: btoa(String.fromCharCode(...new Uint8Array(credential.rawId))),
            type: credential.type
        })
    });
}

WebAuthn 认证(登录)

// 网站端:使用 Passkey 登录
async function authenticateWithPasskey() {
    const challenge = new Uint8Array(32);
    crypto.getRandomValues(challenge);

    try {
        const credential = await navigator.credentials.get({
            publicKey: {
                challenge: challenge,
                rpId: "myapp.com",
                userVerification: "required"
            }
        });

        // 验证成功,发送到服务端确认
        const response = await fetch('/api/verify-passkey', {
            method: 'POST',
            body: JSON.stringify({
                id: credential.id,
                rawId: btoa(String.fromCharCode(...new Uint8Array(credential.rawId))),
                signature: btoa(String.fromCharCode(
                    ...new Uint8Array(credential.response.signature)
                ))
            })
        });
        // 登录成功
    } catch (error) {
        // 用户取消或认证失败,回退到密码登录
        showPasswordLoginForm();
    }
}

原生 App 中使用 Sign in with Apple 作为过渡方案

import AuthenticationServices

// 在 Passkeys 完全可用之前,用 Sign in with Apple 作为无密码方案
func signInWithApple() {
    let provider = ASAuthorizationAppleIDProvider()
    let request = provider.createRequest()
    request.requestedScopes = [.fullName, .email]

    let controller = ASAuthorizationController(authorizationRequests: [request])
    controller.delegate = self
    controller.performRequests()
}

// 处理授权结果
func authorizationController(controller: ASAuthorizationController,
                             didCompleteWithAuthorization authorization: ASAuthorization) {
    if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
        let userID = credential.user
        let email = credential.email
        // 使用 userID 作为用户的唯一标识(跨设备一致)
        signInUser(identifier: userID, email: email)
    }
}

最佳实践

  1. 现在就开始在 Web 端支持 WebAuthn。即使 Passkeys 的完整体验在后续版本才到来,Safari 15 已经支持 WebAuthn API。提前接入可以覆盖使用安全密钥的高级用户。
  2. 同时保留密码登录作为后备。在 Passkeys 推广的过渡期(可能持续 3-5 年),密码仍然是必要的后备方案。但可以在 UI 上优先展示 Passkey 选项。
  3. 用 Sign in with Apple 填补移动端的空白。在 Passkeys 原生 SDK 完善之前,Sign in with Apple 是最接近”无密码”体验的方案。

还有什么值得关注

  • Passkeys 是苹果、Google、Microsoft 三方联合推动的标准,跨平台兼容性是核心设计目标。
  • iCloud Keychain 的密码泄露检测使用差分隐私技术,苹果不会知道你的具体密码。
  • 苹果建议在注册新用户时直接引导创建 Passkey,不再询问密码。
WWDC 2021