首页 > web前端 > js教程 > 正文

BOM中如何操作浏览器的WebAuthn功能?

幻夢星雲
发布: 2025-07-07 18:02:02
原创
257人浏览过

webauthn通过navigator.credentials对象实现无密码认证,核心方法是create()和get()。1. 注册时调用create()生成密钥对,私钥存于认证器,公钥发送服务器;2. 登录时调用get()获取签名断言,发送服务器验证身份。其安全性依赖于公钥加密机制,挑战值防止重放攻击,服务器需严格验证签名、来源、rp id等信息,并检查计数器防克隆。开发中需注意跨域配置、错误处理、兼容性测试及提供备用恢复机制。

BOM中如何操作浏览器的WebAuthn功能?

在BOM(浏览器对象模型)中操作WebAuthn功能,主要围绕navigator.credentials这个全局对象展开。它提供了一套标准化的API,允许网页与用户的硬件安全密钥、指纹识别器或面部识别系统等认证器进行交互,从而实现无密码或多因素认证。简而言之,WebAuthn就是通过这个接口,让你的浏览器能“听懂”并“指挥”本地的安全硬件。

BOM中如何操作浏览器的WebAuthn功能?

解决方案

要实现WebAuthn的注册(创建新凭证)和认证(获取现有凭证),你主要会用到navigator.credentials.create()和navigator.credentials.get()这两个方法。这两个方法都返回一个Promise,你需要异步处理它们的结果。

注册(创建凭证): 当用户首次使用WebAuthn注册时,你需要调用navigator.credentials.create()。这个方法会指示浏览器生成一对新的公钥/私钥,私钥安全地存储在用户的认证器(如指纹传感器、USB密钥)中,而公钥则返回给你的Web应用,你需要将其发送到服务器进行存储。

BOM中如何操作浏览器的WebAuthn功能?
const publicKeyCredentialCreationOptions = {
    challenge: Uint8Array.from('一个随机生成的挑战值,每次注册都应不同', c => c.charCodeAt(0)), // 服务器生成的随机数
    rp: {
        name: "我的酷炫网站", // 网站名称
        id: "yourdomain.com", // 网站域名,用于防止钓鱼
    },
    user: {
        id: Uint8Array.from('用户唯一ID', c => c.charCodeAt(0)), // 用户的唯一标识符
        name: "user@example.com", // 用户名
        displayName: "示例用户",
    },
    pubKeyCredParams: [{ alg: -7, type: "public-key" }], // 推荐的算法类型,-7代表ES256
    timeout: 60000, // 超时时间
    attestation: "direct", // 或 "none", "indirect"
    excludeCredentials: [], // 可选,排除用户已注册的凭证
    authenticatorSelection: {
        authenticatorAttachment: "platform", // "platform" (内置指纹) 或 "cross-platform" (USB密钥)
        userVerification: "required", // "required", "preferred", "discouraged"
    },
};

navigator.credentials.create({ publicKey: publicKeyCredentialCreationOptions })
    .then(credential => {
        // 将 credential.response.attestationObject 和 credential.response.clientDataJSON
        // 以及 credential.id 发送到服务器进行验证和存储
        console.log("注册成功:", credential);
        // 通常需要将 credential.rawId (Base64Url编码), credential.response.clientDataJSON,
        // credential.response.attestationObject, credential.type 等发送到后端
        // 后端会验证这些数据,并存储公钥
    })
    .catch(error => {
        console.error("注册失败:", error);
        // 处理用户取消、超时、不支持等错误
    });
登录后复制

认证(获取凭证): 当用户尝试登录时,你需要调用navigator.credentials.get()。这个方法会提示用户通过他们的认证器(如触摸指纹传感器)来证明身份。成功后,浏览器会返回一个签名过的断言(assertion),你的Web应用需要将其发送到服务器进行验证。

const publicKeyCredentialRequestOptions = {
    challenge: Uint8Array.from('一个随机生成的挑战值,每次认证都应不同', c => c.charCodeAt(0)), // 服务器生成的随机数
    allowCredentials: [], // 可选,指定允许使用的凭证ID列表
    timeout: 60000,
    userVerification: "preferred", // "required", "preferred", "discouraged"
};

navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions })
    .then(credential => {
        // 将 credential.response.authenticatorData, credential.response.clientDataJSON,
        // credential.response.signature, credential.response.userHandle
        // 以及 credential.id 发送到服务器进行验证
        console.log("认证成功:", credential);
        // 后端会根据之前存储的公钥,验证这个断言的签名是否有效
    })
    .catch(error => {
        console.error("认证失败:", error);
        // 处理用户取消、超时、不支持等错误
    });
登录后复制

WebAuthn认证:无密码登录的魔法与机制

WebAuthn之所以能实现无密码登录,其核心在于它巧妙地利用了公钥密码学。我们不再需要记忆复杂的密码,而是依赖于用户持有的“物理凭证”——一个存储了私钥的安全设备,比如你的手机指纹传感器、Windows Hello,或者一个外置的USB安全密钥(如YubiKey)。

BOM中如何操作浏览器的WebAuthn功能?

想象一下这个过程:当你在一个支持WebAuthn的网站注册时,你的浏览器会和你的认证器(比如指纹识别器)“商量”一下,然后生成一对加密密钥:一个公钥和一个私钥。私钥就像一把只有你和你的认证器知道的“秘密钥匙”,它永远不会离开你的设备。公钥则像一把可以公开的“锁”,它被发送到网站的服务器上存储起来。

下次你登录时,网站会给你一个随机的“挑战”(challenge),就像一个只有这一次有效的谜题。你的浏览器会把这个谜题发给你的认证器,认证器用它的“秘密钥匙”(私钥)来“解答”这个谜题,并生成一个“答案”(签名),这个答案再发回给网站。网站用它存储的你的“公开锁”(公钥)来验证这个“答案”是否正确。如果答案正确,就证明是你在操作,因为只有拥有那个“秘密钥匙”的认证器才能生成正确的答案。

这个过程中,你的实际“密码”(私钥)从未离开过你的设备,也从未在网络上传输,这极大降低了密码被窃取或钓鱼攻击的风险。这不就是一种优雅的魔法吗?从用户的角度看,只需轻轻一触或一眼扫过,就完成了身份验证,既安全又便捷。

WebAuthn实现中的常见挑战与应对策略

虽然WebAuthn前景光明,但在实际落地过程中,开发者确实会遇到一些让人头疼的“坑”。这不像传统的密码认证那样直白,它涉及到多方协作(浏览器、认证器、RP服务器),以及对公钥密码学的一些理解。

一个最常见的挑战是跨域问题(Cross-Origin Issues)。WebAuthn对rp.id(Relying Party ID,通常是你的域名)有严格的要求。它必须是当前页面的域名或其可注册的父域。比如,如果你的网站是app.example.com,那么rp.id可以是app.example.com或example.com。但如果你在dev.example.com上测试,而rp.id设置成了prod.example.com,浏览器就会拒绝操作。这是为了防止钓鱼攻击,但初次接触时很容易混淆。我的建议是,开发和生产环境的rp.id要仔细匹配,或者在开发时使用与开发域名一致的rp.id。

其次是用户体验与错误处理。WebAuthn的交互是高度依赖浏览器和操作系统的。用户可能会看到各种提示,比如“请触摸您的安全密钥”、“请验证您的指纹”。如果用户取消了操作、设备不支持、或者认证超时,navigator.credentials.create()或get()的Promise就会被拒绝。你需要捕获这些错误,并向用户提供清晰的反馈,而不是简单地抛出一个通用错误信息。例如,DOMException中的name属性可以告诉你具体是NotAllowedError(用户取消)还是SecurityError(协议问题)。

再来是挑战值(Challenge)的生成和验证。这个挑战值必须是服务器端生成的、加密安全的随机数,并且每次注册或认证都必须是唯一的。它只应使用一次(nonce),以防止重放攻击。如果服务器端没有正确地生成和验证挑战,整个WebAuthn的安全性就形同虚设。这部分是后端的核心安全逻辑,前端只负责传递。

最后,浏览器和设备兼容性也是一个持续的考量。虽然主流浏览器(Chrome, Firefox, Edge, Safari)都支持WebAuthn,但它们对某些特性(如authenticatorSelection.authenticatorAttachment、attestation)的支持程度可能有所不同。此外,用户的操作系统版本和硬件认证器类型也会影响功能可用性。在开发时,最好在多种浏览器和设备上进行测试,并考虑提供优雅降级方案,比如在不支持WebAuthn时回退到密码登录。这不像写一个简单的JavaScript函数那样,它需要对整个生态系统有更全面的认识。

确保WebAuthn流程安全的实践与注意事项

WebAuthn的核心价值在于其安全性,但这种安全性并非自动获得,它需要前端和后端协同工作,并遵循一系列最佳实践。如果处理不当,即使是WebAuthn也可能存在漏洞。

一个至关重要的环节是服务器端对认证断言(Assertion)的严格验证。当navigator.credentials.get()返回一个PublicKeyCredential对象给前端时,前端必须将其发送到后端。后端不能简单地相信前端传来的数据。它需要:

  1. 验证签名: 使用注册时存储的公钥来验证断言的签名是否有效。这是最核心的一步,确保了数据未被篡改且来自合法的认证器。
  2. 验证挑战值: 确保断言中的挑战值与服务器发送给前端的挑战值完全匹配,并且该挑战值是唯一的、未被重用的。
  3. 验证来源(Origin): 确认断言中的clientDataJSON.origin与你的网站域名匹配,防止跨站伪造请求。
  4. 验证RP ID: 确认authenticatorData中的RP ID哈希值与你的网站RP ID匹配。
  5. 检查标志位: 验证authenticatorData中的用户已验证(UV)和用户在场(UP)标志位,确保用户确实进行了交互。
  6. 计数器检查: 认证器会维护一个签名计数器。服务器应存储这个计数器并在每次认证时验证它是否递增。这可以防止认证器被克隆或重放攻击。

此外,安全存储公钥也至关重要。公钥本身不是秘密,但它们必须与正确的用户关联,并存储在一个安全的数据库中。如果公钥被篡改或丢失,用户的WebAuthn认证将失效。

防止钓鱼攻击是WebAuthn设计的初衷之一,但开发者仍需警惕。rp.id的正确设置和验证是关键。如果攻击者能诱骗用户在钓鱼网站上进行WebAuthn操作,并成功注册或认证,那将是灾难性的。因此,除了技术实现,对用户的安全教育也同样重要。

最后,提供备用恢复机制是不可忽视的一点。虽然WebAuthn非常安全和方便,但如果用户的认证器丢失、损坏,或者他们无法访问,他们将无法登录。因此,提供传统的密码登录作为备用选项,或者提供基于邮件/短信的恢复流程,都是必要的。这就像给你的房子除了智能锁,还留了一把传统的钥匙,以防万一。毕竟,技术再先进,也得考虑真实世界中的各种“意外”。

以上就是BOM中如何操作浏览器的WebAuthn功能?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号