JS `WebAuthn` `Attestation` 与 `Assertion`:FIDO2 认证协议细节

咳咳,各位听众,早上好/下午好/晚上好!欢迎来到今天的“WebAuthn:Attestation和Assertion的那些事儿”讲座。今天咱们不搞虚的,直接上干货,把FIDO2认证协议里的Attestation和Assertion这两个关键概念给扒个精光。

一、WebAuthn:一个不只是密码的时代

先简单回顾一下WebAuthn是啥。简单来说,WebAuthn是一种Web API,让网站可以利用生物识别技术(指纹、人脸识别)或者安全密钥(YubiKey之类的)来进行用户认证。它的目标是取代传统的用户名密码,提供更安全、更便捷的登录方式。

核心概念:

  • Authenticator(认证器): 硬件或软件,用于生成和存储密钥,并执行认证操作。比如你的指纹识别器、手机上的安全芯片、或者YubiKey。
  • Relying Party (RP,依赖方): 提供服务的网站或者应用,需要验证用户的身份。也就是你的网站或者应用。

二、Attestation:认证器的“身份证明”

Attestation,中文可以翻译成“证明”。在WebAuthn流程中,它发生在注册阶段,也就是用户第一次将认证器与网站关联的时候。它的作用是让Relying Party(你的网站)知道这个认证器是可信的,并且能够验证该认证器生成的密钥的安全性。

想象一下,你去银行开户,需要提供身份证证明你是你,Attestation就是认证器的“身份证”。

具体来说,Attestation过程包括以下步骤:

  1. 认证器生成密钥对: 认证器内部生成一个公钥-私钥对。私钥永远不会离开认证器。

  2. 认证器创建Attestation Statement: 认证器用自己的Attestation私钥(一个由认证器制造商提供的,根证书存在于RP侧的密钥)对一些数据进行签名,生成一个Attestation Statement。这个Statement里包含了:

    • 公钥(用于后续的Assertion阶段)
    • 关于认证器的信息(制造商、型号、序列号等)
    • 一个叫做attStmt的结构体,包含了签名本身以及证明签名有效性的证书链。
  3. 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过程包括以下步骤:

  1. RP生成Challenge: Relying Party生成一个随机的Challenge,发送给客户端。这个Challenge用于防止重放攻击。

  2. 认证器使用私钥签名: 认证器使用之前注册时生成的私钥对一些数据进行签名,生成一个Assertion。这个Assertion里包含了:

    • Challenge
    • Relying Party ID
    • 用户ID
    • 签名
  3. 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有了更深入的理解。有什么问题,欢迎提问!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注