【问题标题】:Authenticating with public key in javascript在javascript中使用公钥进行身份验证
【发布时间】:2022-12-20 07:22:34
【问题描述】:

我尝试按照https://webauthn.guide 的说明为我站点中的用户注册生物识别登录。

注册 Javascript 函数是这样的:

var randomStringFromServer = "123456";
async function CreateANew()
{
    var bz = Uint8Array.from(randomStringFromServer);
    const publicKeyCredentialCreationOptions = {
        challenge: bz,
    rp: {
        name: "mysite.COM",
        id: "mysite.com",
    },
    user: {
        id: Uint8Array.from(
            'some_user_name'),
        name: 'some_name',
        displayName: 'some_display_name',
    },
    pubKeyCredParams: [{alg: -7, type: "public-key"}],
    authenticatorSelection: {
        
    },
    timeout: 60000,
    attestation: "direct"
};
   const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
    });
    if (!credential)
        return;
    
    // decode the clientDataJSON into a utf-8 string
    const utf8Decoder = new TextDecoder('utf-8');
    const decodedClientData = utf8Decoder.decode(credential.response.clientDataJSON);
    // parse the string as an object
    const clientDataObj = JSON.parse(decodedClientData);
    
    const decodedAttestationObj = CBOR.decode(
        credential.response.attestationObject);


        const {authData} = decodedAttestationObj;

        // get the length of the credential ID
        const dataView = new DataView(
            new ArrayBuffer(2));
        const idLenBytes = authData.slice(53, 55);
        idLenBytes.forEach(
            (value, index) => dataView.setUint8(
                index, value));
        const credentialIdLength = dataView.getUint16();

        // get the credential ID
        const credentialId = authData.slice(
            55, 55 + credentialIdLength);

        // get the public key object
        const publicKeyBytes = authData.slice(
            55 + credentialIdLength);

        // the publicKeyBytes are encoded again as CBOR
        const publicKeyObject = CBOR.decode(
            publicKeyBytes.buffer);
                        

    let CID = credentialId;
    let PID = publicKeyBytes;
    console.log(credentialId);
    $.ajax({
        url: "bio.php",
        method: "POST",
        data: {"create": 2, "type": <?= $tyx ?>, "uid" : <?= $u ?>, "challenge": clientDataObj.challenge, "origin": clientDataObj.origin,"ctype": clientDataObj.type,"authData": decodedAttestationObj.authData,"fmt" : decodedAttestationObj.fmt, "credentialID" : CID, "publicKeyBytes" : PID },
        success: function (result) {
            $("#result").html(result);
            if (result.startsWith("OK"))
                window.location = "bio.php";
        }
    });

这有效,我在我的 PHP 数据库中取回了一个 credentialID 和一个 publicKeyBytes 数组。

<?php

 $ar = serialize($_POST['credentialID']); // and then store $ar to database

但是,当我尝试对用户进行身份验证时:

// $or = PHP array with the credentialID taken from the database
// $or = unserialize(...);
async function Login()
    {
        var bz = Uint8Array.from(randomStringFromServer);
        let id2 = "<?= implode(",",$or) ?>";
        let id2a = id2.replace(/, +/g, ",").split(",").map(Number);
        let id3 =  Uint8Array.from(id2a);
        console.log(id3);

        const publicKeyCredentialRequestOptions = {
        challenge: bz,                
        allowCredentials: [{
            id: id3,
            type: 'public-key',
            
        }],
timeout: 60000,

}

    const credential = await navigator.credentials.get({
        publicKey: publicKeyCredentialRequestOptions
    });
}

这次我只在 Chrome 中看到“插入您的 USB 密钥”。它似乎无法识别我的 credentialID。

我究竟做错了什么?

【问题讨论】:

    标签: javascript webauthn


    【解决方案1】:

    凭证 ID 很可能在此过程中的某个地方被损坏。尝试在提取后立即登录到控制台:

    console.log(btoa(String.fromCharCode.apply(null, new Uint8Array(CID)));
    

    在进行身份验证调用之前再次:

    console.log(btoa(String.fromCharCode.apply(null, new Uint8Array(id3)));
    

    它们应该是相同的值。


    作为旁白:

    用户:{ id: Uint8Array.from('some_user_name'),

    user.id should not include any identifiable information,所以用户名在那里是一个错误的值。我建议在您的数据库中为每个用户生成一个 128 位随机值以用作用户 ID。

    // get the public key object
    const publicKeyBytes = authData.slice(55 + credentialIdLength);

    扩展名may follow 公钥,这将接他们。如果您的 CBOR 解码器忽略尾随数据,那可能没问题。 (您也可以通过在证明响应中调用getPublicKey 来获取公钥,并且您不必以这种方式处理 CBOR。)

    【讨论】:

    • 是的,它们是相同的值:(
    • 只是为了确保我理解:当您创建凭据时,您使用的是 Windows Hello 而不是安全密钥?返回的凭据 ID 与您传递给同一台机器上的断言调用的内容相匹配,但 Hello 无法识别它并认为它必须在安全密钥上?如果是这样,您可以记录整个 authdata 的 base64 并给我那个,加上您从中获得的凭证 ID 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2013-10-08
    • 1970-01-01
    • 2015-10-20
    • 2020-08-19
    • 2015-01-10
    • 2012-05-16
    相关资源
    最近更新 更多