1、webauthn介绍
官网:https://webauthn.io/
1.1、什么是webauthn?
webauthn即Web Authentication,是一个符合W3C标准的Web认证规范。它通过公私钥加密技术,实现无密码认证,用户仅需通过pin码、指纹、面部识别、usb key等方式,即可实现整套注册登录流程。使用webauthn,web网站的整个认证流程将得到极大简化,同时,相比传统的密码认证,webauthn的安全性更高。
1.2、主流web认证方式和wenauthn对比
目前使用最多的认证方式有三种,分别是账号密码登录、短信(邮箱)验证登录、第三方登录。
1.2.1、账号密码登录
最古老的认证方式,缺点一大堆,大部分的密码都是弱密码,或者是与本人姓名、生日等有关的密码;大部分人的常用密码就那么几个,不管登录什么应用,都是同一个密码;偶尔换个密码,很快就忘了,账号也会忘掉。
1.2.2、短信(邮箱)验证登录
相比账号密码安全一些。有时候等不到验证码,或者很慢。用户的手机号被泄露,收到大量垃圾短信,接到大量广告电话,不胜其烦。现在配合运营商,可以不需要验证码,实现手机号一键登录了,但是前提是,必须是正在使用流量的手机号才行,比如卡1开了5g数据连接,卡2关闭了数据连接,则手机号一键登录只支持卡1,不支持卡2。
1.2.3、第三方登录
用qq,微信登录完,还会强行要求你绑定手机号,比较繁琐。
1.2.4、webauthn登录
优点:
①、不需要密码,但需要用户自己输入一个账号,可以是手机号,邮箱等。
②、通过设备自带的认证方式登录,比如PIN、指纹、面部识别、usb key。
③、极简登录流程,用户体验好。
④、安全性高,服务器不存储任何密码。
缺点:
①、只能是web应用才可以。
②、换设备登录问题。
2、webauthn原理
在介绍原理之前,先简单介绍一下公钥、私钥是什么东西,防止有人不清楚。明确以下三点,就能读懂接下来的内容:
①、公钥和私钥是成对生成的。
②、公钥可以随便公开,私钥不可以泄露。
③、用公钥加密的数据,只有用私钥才能解密;反之,用私钥加密的数据,也只有用公钥才能解密,公钥私钥属于非对称加密技术。
webauthn 的原理并不复杂,它的核心是基于公钥的加密技术。在 webauthn 中,用户的身份认证是通过公钥和私钥来实现的。这很像我们平常使用配置了公私钥的 SSH 登录服务器的过程,只不过 webauthn 是在浏览器中实现的。
webauthn 使用非对称加密技术,其中密钥对包括公钥和私钥。公钥用于注册和验证身份,私钥只在用户的设备中保留,用于对挑战进行签名,从而实现了更加安全的认证方式。WebAuthn支持多种生物识别技术,提供了更方便的认证体验,避免了传统密码认证带来的一些安全风险。此外,WebAuthn还可以防止钓鱼攻击和恶意软件攻击,因为它不需要用户记住或输入密码,也不需要提供个人信息或电话号码等。
2.1、组成部分
webauthn 由以下三个组成部分组成:
①. 用户代理(User Agent):用户代理是指浏览器或者其他支持 WebAuthn 的客户端,它负责与用户进行交互,收集用户的身份认证信息
,并将其发送给服务器。
②. 身份验证器(Authenticator):身份验证器是指用于生成公钥和私钥
的设备,如手机、USB 密钥或生物识别器。Windows Hello 和 macOS 的 Touch ID 也都是常见的身份验证器。
③. Relying Party:Relying Party 是指需要进行身份认证
的网站或应用程序,它负责生成挑战(Challenge)并将其发送给用户代理,然后验证用户代理发送的签名结果
。
上述三者在两个不同的用例(注册和认证)中协同工作,如下图所示。图中的各个实体之间的所有通信都由用户代理(通常是Web浏览器)处理。
2.2、架构实现
webauthn 用公钥证书代替了密码,完成用户的注册和身份认证(登录)。它更像是现有身份认证的增强或补充。为了保证通信数据安全,一般基于HTTPS
(TLS)通信。在这个过程中,有4个模块。
Server(服务端):
它可以被认为一个依赖方(Relying Party),它会存储用户的公钥
并负责用户的注册
、认证
。
JavaScript(Js脚本):
调用浏览器API,与Server进行通信,发起注册或认证过程
。
Browser(浏览器):
需要包含WebAuthn的Credential Management API提供给js调用,还需要实现与认证模块
进行通信
,由浏览器统一封装硬件设备的交互。
Authenticator(认证模块):
它能够创建、存储、检索身份凭证
。它一般是个硬件设备
(智能卡、USB,NFC等),也可能已经集成到了你的操作系统(比如Windows Hello
,MacOS的Touch ID
等)。
3、webauthn流程
首先明确,在webauthn认证流程中,有三个参与者:
①、后端服务server
②、浏览器
③、用户设备中的认证器:比如Windows Hello,MacOS的Touch ID,他负责生成公私钥,签名。
3.1、注册流程
①、用户输入username(理解为账号,可以是手机号、邮箱等),前端发起注册请求,把username传到后端。
②、后端拿到username后,先验证该username是否被注册;然后生成挑战;然后将username、挑战缓存起来(可以用session或redis);然后返回给前端挑战、用户信息、依赖方信息。
(1)挑战:一个随机的ByteArray转成的base64字符串。
(2)用户信息:包含id,name,displayName;id由后端随机生成(出于安全考量,这应尽可能不与任何用户信息相关联,如不要包含用户名、用户邮箱等),name即username,displayName为展示名,可以随便。(3)依赖方信息:包含后端指定的签名算法、认证方式、所在域名等信息。
③、浏览器请求认证器,生成公钥私钥,请求认证器的具体方式如下:
navigator.credentials.create(credentialCreateOptions).then(publicKeyCredential => {
console.log(publicKeyCredential)
})
其中,参数credentialCreateOptions比较复杂,他包含这些内容:
{
publicKey: {
challenge, //挑战
rp: { //依赖方信息
id,
name
},
user: { //用户信息
id,
name,
displayName
},
pubKeyCredParams: [ //算法列表
{
type: "public-key",
alg
}
],
authenticatorSelection: { //指定的认证器类型(可选)
authenticatorAttachment,
userVerification
},
excludeCredentials: [ //用于标识要排除的凭证
{
id,
transports: [],
type: "public-key"
}
],
timeout //超时时间
}
}
参数说明如下:
-
challenge: Uint8Array:转换为 Uint8Array 的挑战,长度至少为 16,建议为 32
-
rp: Object:依赖方信息,其中有一项为必须:
○ rp.id: String:(可选)依赖方 ID,必须为当前域名或为当前域名的子集的域名(不是子域名)。如域名为 test.123.example.com,则依赖方 ID 可以是 test.123.example.com, 123.example.com 或 example.com。不指定则默认使用当前域名
○ rp.name: String:依赖方名称,用于方便用户辨认
-
user: Object:用户信息,其中有三项为必须:
○ user.id: Uint8Array:转换为 Uint8Array 的字符串。出于安全考量,这应尽可能不与任何用户信息相关联,如不要包含用户名、用户邮箱等
○ user.name: String:登录用户名
○ user.dispalyName: String:用于显示的用户名称,显示与否的具体行为取决于浏览器
-
pubKeyCredParams: Array:一个算法列表,指明依赖方接受哪些签名算法。列表的每一项都是一个对象,拥有两个属性:
○ pubKeyCredParams[].type: String:值只能为 “public-key”
○ pubKeyCredParams[].alg: Number:一