咳咳,各位听众,早上好/下午好/晚上好!欢迎来到今天的“WebAuthn:Attestation和Assertion的那些事儿”讲座。今天咱们不搞虚的,直接上干货,把FIDO2认证协议里的Attestation和Assertion这两个关键概念给扒个精光。
一、WebAuthn:一个不只是密码的时代
先简单回顾一下WebAuthn是啥。简单来说,WebAuthn是一种Web API,让网站可以利用生物识别技术(指纹、人脸识别)或者安全密钥(YubiKey之类的)来进行用户认证。它的目标是取代传统的用户名密码,提供更安全、更便捷的登录方式。
核心概念:
- Authenticator(认证器): 硬件或软件,用于生成和存储密钥,并执行认证操作。比如你的指纹识别器、手机上的安全芯片、或者YubiKey。
- Relying Party (RP,依赖方): 提供服务的网站或者应用,需要验证用户的身份。也就是你的网站或者应用。
二、Attestation:认证器的“身份证明”
Attestation,中文可以翻译成“证明”。在WebAuthn流程中,它发生在注册阶段,也就是用户第一次将认证器与网站关联的时候。它的作用是让Relying Party(你的网站)知道这个认证器是可信的,并且能够验证该认证器生成的密钥的安全性。
想象一下,你去银行开户,需要提供身份证证明你是你,Attestation就是认证器的“身份证”。
具体来说,Attestation过程包括以下步骤:
-
认证器生成密钥对: 认证器内部生成一个公钥-私钥对。私钥永远不会离开认证器。
-
认证器创建Attestation Statement: 认证器用自己的Attestation私钥(一个由认证器制造商提供的,根证书存在于RP侧的密钥)对一些数据进行签名,生成一个Attestation Statement。这个Statement里包含了:
- 公钥(用于后续的Assertion阶段)
- 关于认证器的信息(制造商、型号、序列号等)
- 一个叫做
attStmt
的结构体,包含了签名本身以及证明签名有效性的证书链。
-
RP验证Attestation Statement: Relying Party收到Attestation Statement后,会做以下验证:
- 验证签名是否有效(使用认证器制造商提供的根证书)。
- 验证证书链的有效性。
- 验证认证器的信息是否符合预期(例如,是否是指定的制造商和型号)。
- 根据Attestation类型,进行特定的安全检查。
Attestation类型:
| Attestation类型 | 描述 | 安全性 | 隐私性 |
| ————- | ———————————————————————————————————————————————————————————————————————————- | —- | —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————-,
| 签名的安全性,验证复杂度较高。 |
| 直接认证(Full Attestation) | 最安全的,认证器会提供一个由认证器制造商颁发的证书链。这个证书链最终会连接到认证器制造商的根证书,Relying Party可以通过验证这个证书链来确认认证器的真实性。 | 高 | 隐私性较低。因为Attestation Statement中包含认证器的序列号等信息,可能会被用于追踪用户。 |
| 间接认证(Indirect Attestation) | 认证器使用一个中间证书进行签名,这个中间证书由一个中间CA颁发,再由根CA颁发给中间CA。RP需要拿到这个中间CA的证书。安全性略低于直接认证,因为需要信任中间CA。 | 中 | 隐私性适中。 |
| 匿名认证(Attestation CA) | 认证器使用一个由匿名CA颁发的证书进行签名。匿名CA的证书不包含任何关于认证器的身份信息。安全性取决于匿名CA的安全性。 | 低 | 隐私性较高。可以有效防止认证器被追踪。 |
| 无认证(None Attestation) | 认证器不提供任何Attestation Statement。Relying Party无法验证认证器的真实性,只能信任用户。 | 最低 | 隐私性最高。 |
代码示例 (简化版 – 服务器端验证Attestation):
// 假设attestationStatement是从客户端传过来的
async function verifyAttestation(attestationStatement) {
// 1. 获取Attestation类型 (attestationStatement.format)
const format = attestationStatement.format;
// 2. 根据Attestation类型进行验证
switch (format) {
case 'fido-u2f':
// U2F Attestation验证逻辑 (比较简单,略过)
break;
case 'packed':
// Packed Attestation验证逻辑 (比较复杂,需要验证证书链)
// 2.1 获取证书链
const certificateChain = attestationStatement.attStmt.certInfo;
// 2.2 验证证书链 (需要从认证器厂商获取根证书)
const rootCert = getRootCertificateFromManufacturer(attestationStatement.attStmt.alg);
// 2.3 验证签名 (使用证书链中的证书)
const isValidSignature = verifySignature(attestationStatement.attStmt.sig, dataToBeSigned, certificateChain);
if (!isValidSignature) {
throw new Error('Invalid signature');
}
break;
case 'none':
// None Attestation: 无需验证
break;
default:
throw new Error('Unsupported attestation format');
}
// 3. 验证其他参数 (例如,nonce是否匹配)
// ...
return true; // Attestation验证成功
}
// (简化版) 获取认证器厂商根证书的函数
function getRootCertificateFromManufacturer(algorithm) {
// 实际中需要根据算法和认证器信息从数据库或配置文件中获取
// 这里只是一个示例
if(algorithm === -7){ //ES256
return '-----BEGIN CERTIFICATE-----n...根证书内容...n-----END CERTIFICATE-----';
}
return null;
}
// (简化版) 验证签名的函数
function verifySignature(signature, data, certificateChain) {
// 实际中需要使用Node.js的crypto模块进行签名验证
// 这里只是一个占位符
try {
// 获取证书
const cert = certificateChain;
const publicKey = crypto.createPublicKey(cert);
// 验证签名
const verifier = crypto.createVerify('SHA256');
verifier.update(data);
const result = verifier.verify(publicKey, signature, 'base64');
return result;
} catch (error) {
console.error('签名验证失败:', error);
return false;
}
}
注意事项:
- Attestation 验证是非常重要的安全环节。如果验证不当,可能会导致恶意认证器被注册,从而威胁整个系统的安全。
- 不同的认证器厂商使用的 Attestation 方式可能不同,需要根据具体情况进行处理。
- 验证Attestation需要维护一个可信任的认证器厂商根证书列表。
三、Assertion:用户登录的“通行证”
Assertion,中文可以翻译成“断言”。它发生在认证阶段,也就是用户登录的时候。它的作用是让Relying Party验证用户确实拥有之前注册的认证器。
想象一下,你拿着身份证去银行取钱,银行要验证你的身份证和本人是否一致,Assertion就是这个验证的过程。
具体来说,Assertion过程包括以下步骤:
-
RP生成Challenge: Relying Party生成一个随机的Challenge,发送给客户端。这个Challenge用于防止重放攻击。
-
认证器使用私钥签名: 认证器使用之前注册时生成的私钥对一些数据进行签名,生成一个Assertion。这个Assertion里包含了:
- Challenge
- Relying Party ID
- 用户ID
- 签名
-
RP验证Assertion: Relying Party收到Assertion后,会做以下验证:
- 验证签名是否有效(使用之前注册时保存的公钥)。
- 验证Challenge是否与之前发送的Challenge一致。
- 验证Relying Party ID是否与自己的ID一致。
- 验证用户ID是否与数据库中存储的用户ID一致。
- 检查用户是否存在。
- 检查是否满足用户验证的要求。
- 检查用户操作是否合法。
代码示例 (简化版 – 服务器端验证Assertion):
// 假设assertionResponse是从客户端传过来的
async function verifyAssertion(assertionResponse, expectedChallenge, user) {
// 1. 获取公钥
const publicKey = user.publicKey; // 从数据库中获取之前注册时保存的公钥
// 2. 构造要签名的数据
const dataToBeSigned = constructAssertionData(
expectedChallenge,
assertionResponse.response.authenticatorData,
assertionResponse.response.clientDataJSON
);
// 3. 验证签名
const isValidSignature = verifySignature(assertionResponse.response.signature, dataToBeSigned, publicKey);
if (!isValidSignature) {
throw new Error('Invalid signature');
}
// 4. 验证其他参数
// 4.1 验证Challenge
const clientData = JSON.parse(Buffer.from(assertionResponse.response.clientDataJSON, 'base64').toString('utf8'));
if (clientData.challenge !== expectedChallenge) {
throw new Error('Challenge mismatch');
}
// 4.2 验证Relying Party ID
if (clientData.origin !== 'https://your-website.com') {
throw new Error('Origin mismatch');
}
// 5. 验证认证器数据 (authenticatorData)
// ... (例如,检查用户是否存在性标志)
return true; // Assertion验证成功
}
// 构造要签名的数据的函数 (简化版)
function constructAssertionData(challenge, authenticatorData, clientDataJSON) {
const clientDataHash = crypto.createHash('sha256').update(Buffer.from(clientDataJSON, 'base64')).digest();
return Buffer.concat([
Buffer.from(authenticatorData, 'base64'),
clientDataHash
]);
}
// (复用注册时的签名验证函数)
// (简化版) 验证签名的函数
function verifySignature(signature, data, publicKey) {
// 实际中需要使用Node.js的crypto模块进行签名验证
// 这里只是一个占位符
try {
const publicKeyObject = crypto.createPublicKey({
key: Buffer.from(publicKey, 'base64'),
format: 'jwk'
});
// 验证签名
const verifier = crypto.createVerify('SHA256');
verifier.update(data);
const result = verifier.verify(publicKeyObject, Buffer.from(signature, 'base64'));
return result;
} catch (error) {
console.error('签名验证失败:', error);
return false;
}
}
注意事项:
- Challenge 的生成和验证是防止重放攻击的关键。
- Relying Party ID 必须与自己的ID一致,防止中间人攻击。
- 需要根据认证器数据(
authenticatorData
)进行额外的安全检查,例如,检查用户是否存在性标志。
四、Attestation vs. Assertion:异同点
特性 | Attestation | Assertion |
---|---|---|
阶段 | 注册 | 认证 |
目的 | 验证认证器的真实性 | 验证用户拥有该认证器 |
密钥 | 认证器制造商的私钥 (用于签名Attestation Statement) | 用户注册时生成的私钥 (用于签名Assertion) |
验证方 | Relying Party | Relying Party |
包含的信息 | 认证器信息、公钥、签名、证书链 | Challenge、Relying Party ID、用户ID、签名 |
安全性 | 验证认证器是否可信,防止伪造认证器 | 验证用户身份,防止重放攻击和中间人攻击 |
隐私性 | 可能泄露认证器信息,存在追踪风险 | 隐私性相对较高 |
总结:
Attestation和Assertion是WebAuthn认证流程中两个至关重要的环节。Attestation保证了认证器的可信性,Assertion保证了用户的身份验证。理解这两个概念,才能更好地使用WebAuthn,构建更安全、更便捷的身份认证系统。
五、一点小幽默
想象一下,Attestation就像是认证器的“户口本”,证明它是个好公民,值得信赖。而Assertion就像是用户的“身份证”,证明你就是你,可以合法使用这个认证器。
如果Attestation出了问题,就像是拿了个假户口本,会导致整个系统都认为你是合法公民,但实际上你可能是个黑户。如果Assertion出了问题,就像是拿了个假身份证,会导致你无法证明自己的身份,无法登录系统。
所以,Attestation和Assertion都非常重要,缺一不可!
好了,今天的讲座就到这里。希望大家对WebAuthn的Attestation和Assertion有了更深入的理解。有什么问题,欢迎提问!