一个没有密码的世界
一个痛苦的事实
有更好的方法
工作原理
进一步阅读和资源
概括
面对现实吧,如今我们的生活已经离不开密码。事实上,我们的整个网络生活都依赖于密码。但密码不仅会给用户带来诸多问题,也会给我们开发者带来诸多问题。
一个痛苦的事实
大多数人在访问的多个网站上都会使用弱密码(而且可能都是一样的)。社交媒体、电子邮件、生产力工具等等,它们都有不同的密码策略,大多数用户都会想方设法绕过这些策略,比如使用弱密码,或者在便条上写一个强密码🤷🏽♂️。
事实上,由于黑客攻击而发生的所有数据泄露事件中有 81% 都是利用被盗或弱密码造成的。
有更好的方法
但由于W3C和FIDO的巨大努力,我们不必事事都使用密码。Web 身份验证 API,又称 Web 身份验证 API,WebAuthn
是一个相当新的规范,它引入了一种无需密码的全新身份验证方式,并且与密码同时进行。
谷歌、微软、Yubico 等业内巨头都参与了该规范的推广。该 API 允许服务器使用公钥加密技术(而非密码)来注册和验证用户身份。
Windows Hello、Apple 的 Touch ID、Yubikey 设备都是另一种无需密码的身份验证机制的例子。它们使用生物识别技术或硬件设备来实现这一点。
工作原理
从 1000ft 开始,您将不再使用密码,而是使用为网站生成的密钥对(公钥和私钥) 。
私钥安全地存储在用户的设备上,而公钥连同随机生成的凭证 ID 一起发送到 Web 服务器进行存储,以便稍后用于验证该特定用户。
总体而言,WebAuthn 依赖于三个主要方面:
- 认证器(进行认证和验证的设备)
- 依赖方(Web 应用程序所有者)
- 浏览器的 Web 身份验证 API
流程相当简单,第一步是注册,然后是身份验证。
注册凭证
与密码验证流程相同,其中 Web 服务器通常提供一个表单供用户输入密码,然后将其发送回服务器进行验证。
WebAuthn 与之非常相似,但依赖方不是要求输入密码,而是要求输入公钥。
![]() |
---|
图片来自 WebAuthn.io |
当提示用户输入凭证时,navigator.credentials.create()
使用:
const credential = await navigator.credentials.create(
{
publicKey: publicKeyCredentialCreationOptions,
}
)
如果你想知道它是什么publicKeyCredentialCreationOptions
样子的,它包含一堆必填和可选字段:
const publicKeyCredentialCreationOptions = {
challenge: Uint8Array.from(
randomStringFromServer,
c => c.charCodeAt(0)
),
rp: {
name: 'Google',
id: 'accounts.google.com',
},
user: {
id: Uint8Array.from('5T9AFCUZSL8', c =>
c.charCodeAt(0)
),
name: 'me@yashints.dev',
displayName: 'Yaser',
},
pubKeyCredParams: [
{ alg: -7, type: 'public-key' },
],
authenticatorSelection: {
authenticatorAttachment: 'cross-platform',
},
timeout: 60000,
attestation: 'direct',
}
challenge
:选项中最重要的部分是挑战。它是服务器上随机生成的字节,用于防止回复攻击。
rp
:代表依赖方,是用户尝试注册的 Web 服务器。
user
:这是注册服务的最终用户。id
用于将公钥与该用户关联,但建议不要将其用作个人身份信息。
pubKeyCredPrams
:指定服务器可以接受哪些类型的公钥。
authenticatorSelection
:可选字段,用于帮助依赖方对允许注册的身份验证器进行进一步的限制。其可能的值(platform
例如 Windows Hello 或cross-platform
Yubikey)可在规范中找到。
timeout
:用户必须响应注册提示的时间(以毫秒为单位)。
attestation
:此参数由身份验证器返回,包含可用于追踪用户的信息。它表明认证对本次注册事件的重要性。例如,如果none
使用 ,则表示服务器不关心此认证。indirect
表示服务器将允许匿名认证数据。direct
表示服务器需要来自身份验证器的数据。通常,这涉及注册过程中的用户隐私。
从调用返回的对象create()
包含一个公钥和用于验证用户的其他属性:
console.log(credential);
PublicKeyCredential {
id: 'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...',
rawId: ArrayBuffer(59),
response: AuthenticatorAttestationResponse {
clientDataJSON: ArrayBuffer(121),
attestationObject: ArrayBuffer(306),
},
type: 'public-key'
}
依赖方验证注册数据
一旦服务器接收到公钥以及注册数据的其他属性,就会有一个程序来验证该数据。
当然,具体实现取决于你使用的语言,但如果你想了解如何实现这些步骤,可以参考一些示例。Duo Labs 已经提供了Go和Python 的完整实现。
使用 WebAuthn 进行身份验证
完成注册后,用户可以向网站进行身份验证。注册过程中,用户会收到一个断言,表明他们拥有私钥。该断言包含使用私钥签名的签名。Web 服务器在注册过程中使用公钥来验证这一点。
身份验证流程如下所示:
![]() |
---|
图片来自 WebAuthn.io |
调用该navigator.credentials.get()
方法生成断言,证明用户拥有私钥。这将检索注册期间生成的包含签名的凭证。
const credential = await navigator.credentials.get(
{
publicKey: publicKeyCredentialRequestOptions,
}
)
该publicKeyCredentialRequestOptions
对象包含许多由服务器指定的强制和可选属性:
const publicKeyCredentialRequestOptions = {
challenge: Uint8Array.from(
randomStringFromServer,
c => c.charCodeAt(0)
),
allowCredentials: [
{
id: Uint8Array.from(credentialId, c =>
c.charCodeAt(0)
),
type: 'public-key',
transports: ['usb', 'ble', 'nfc'],
},
],
timeout: 60000,
}
这个对象中最有趣的部分是 transport 属性。服务器可以选择指定其偏好的传输方式,例如 USB、NFC 和蓝牙。
返回的对象是一个PublicKeyCredential
对象,但与之前注册时的对象稍有不同。
console.log(assertion);
PublicKeyCredential {
id: 'SSX9lKQmbqdGtbcHDTBsvpu4sjseh4cg2TxSvr4ADSUlN...',
rawId: ArrayBuffer(59),
response: AuthenticatorAssertionResponse {
authenticatorData: ArrayBuffer(191),
clientDataJSON: ArrayBuffer(118),
signature: ArrayBuffer(70),
userHandle: ArrayBuffer(10),
},
type: 'public-key'
}
有关此对象的更多信息,请参阅规范。
验证身份验证数据
获取断言后,将其发送到服务器进行验证。验证无误后,使用存储的公钥验证签名。
const storedCredential = await getCredentialFromDatabase(
userHandle,
credentialId
)
const signedData =
authenticatorDataBytes + hashedClientDataJSON
const signatureIsValid = storedCredential.publicKey.verify(
signature,
signedData
)
if (signatureIsValid) {
return 'Hooray! User is authenticated! 🎉'
} else {
return 'Verification failed. 😭'
}
进一步阅读和资源
以下资源是进一步阅读的良好起点:
- Webauthn.io:Due Labs 创建了这个有用的资源,其中包含所有源代码和示例用例以及精美的插图。
- WebAuthn 和 FIDO2 框架的发展:一篇信息丰富的博客文章,介绍了一些进展并展示了每个主要浏览器和该领域贡献者的兼容性。
- 源代码:此 GitHub repo 包含 Due Labs 为演示该功能而创建的所有源代码。
- 互联网大日子:W3C 标准化 WebAuthn
- Yubico 的演示站点:从最终用户的角度演示该过程
概括
我们见证了这项令人惊叹的功能的实现是多么简单直接。如果您正在开发一个全新的项目,我强烈建议您一定要考虑实现它,让用户能够无密码地使用🔥👊🏻。对于当前的产品来说,这可以成为一个转折点,通过简化流程中最重要的部分来吸引更多用户加入系统😊。
文章来源:https://dev.to/yashints/a-world-without-passwords-21a