Javascript 如何在移动设备上与WebAuthn一起使用FIDO凭据

Javascript 如何在移动设备上与WebAuthn一起使用FIDO凭据,javascript,nfc,fido-u2f,webauthn,Javascript,Nfc,Fido U2f,Webauthn,我已经使用内置的firefox和chrome以及javascript U2F API实现了基于桌面浏览器的U2F。我遵循了这里的基本配方: 对于每个物理设备,我有4个属性: 证书 钥匙柄 公钥 柜台 我相信,但我不确定,在获取了有关此物理设备的信息后,我现在可以在移动设备上呈现完全相同的网页时重新调整其用途,以实现WebAuthn,而不是呈现网页供用户进行身份验证,而是呈现移动操作系统本机界面以请求NFC身份验证(如果设备具有NFC) 我试图使用上面的4个属性来呈现带有nav.creden

我已经使用内置的firefox和chrome以及javascript U2F API实现了基于桌面浏览器的U2F。我遵循了这里的基本配方:

对于每个物理设备,我有4个属性:

  • 证书
  • 钥匙柄
  • 公钥
  • 柜台
我相信,但我不确定,在获取了有关此物理设备的信息后,我现在可以在移动设备上呈现完全相同的网页时重新调整其用途,以实现WebAuthn,而不是呈现网页供用户进行身份验证,而是呈现移动操作系统本机界面以请求NFC身份验证(如果设备具有NFC)

我试图使用上面的4个属性来呈现带有nav.credentials.get的javascript,但是我被卡住了

我不清楚以下哪一项是正确的

A) 您可以使用在桌面web上的U2F设备注册过程中收集和验证的凭据/信息,通过web authn在移动设备上进行身份验证

B) 如果您希望在移动设备上使用webauthn,以便触发本机移动NFC身份验证过程,则除了常规U2F流之外,您还必须秘密处理webauthn注册(通过“秘密”我不是说你故意不告诉用户他们正在这样做,而是说,用户不知道A和B之间的区别)

按照上面链接的示例,他们的javascript类似于:

var appId = <%= @app_id.to_json.html_safe %>
var registerRequests = <%= @registration_requests.to_json.html_safe %>;
var signRequests = <%= @sign_requests.as_json.to_json.html_safe %>;

u2f.register(appId, registerRequests, signRequests, function(registerResponse) {
  var form, reg;

  if (registerResponse.errorCode) {
    return alert("Registration error: " + registerResponse.errorCode);
  }

  form = document.forms[0];
  response = document.querySelector('[name=response]');

  response.value = JSON.stringify(registerResponse);

  form.submit();
});
var appId = <%= @app_id.to_json.html_safe %>
var registerRequests = <%= @registration_requests.to_json.html_safe %>;
var signRequests = <%= @sign_requests.as_json.to_json.html_safe %>;


var options = {
  challenge: new Uint8Array([/* bytes sent from the server */]),
  rpId: "example.com" /* will only work if the current domain
                         is something like foo.example.com */
  userVerification: "preferred",
  timeout: 60000,     // Wait for a minute
  allowCredentials: [
    {
      transports: "usb",
      type: "public-key",
      id: new Uint8Array(26) // actually provided by the server
    },
    {
      transports: "internal",
      type: "public-key",
      id: new Uint8Array(26) // actually provided by the server
    }
  ],
  extensions: {
    uvm: true,  // RP wants to know how the user was verified
    loc: false,
    txAuthSimple: "Could you please verify yourself?"
  }
};

navigator.credentials.get({ "publicKey": options })
    .then(function (credentialInfoAssertion) {
    // send assertion response back to the server
    // to proceed with the control of the credential

    // update the hidden form input then
    form.submit();
}).catch(function (err) {
     console.error(err);
});
var-appId=
var registerRequests=;
var signRequests=;
u2f.寄存器(appId、registerRequests、signRequests、函数(registerResponse){
var形式,reg;
if(registerResponse.errorCode){
返回警报(“注册错误:+registerResponse.errorCode”);
}
表单=文档。表单[0];
response=document.querySelector(“[name=response]”);
response.value=JSON.stringify(registerResponse);
表单提交();
});
在这里使用mozilla示例:

我正试图将其改编成如下内容:

var appId = <%= @app_id.to_json.html_safe %>
var registerRequests = <%= @registration_requests.to_json.html_safe %>;
var signRequests = <%= @sign_requests.as_json.to_json.html_safe %>;

u2f.register(appId, registerRequests, signRequests, function(registerResponse) {
  var form, reg;

  if (registerResponse.errorCode) {
    return alert("Registration error: " + registerResponse.errorCode);
  }

  form = document.forms[0];
  response = document.querySelector('[name=response]');

  response.value = JSON.stringify(registerResponse);

  form.submit();
});
var appId = <%= @app_id.to_json.html_safe %>
var registerRequests = <%= @registration_requests.to_json.html_safe %>;
var signRequests = <%= @sign_requests.as_json.to_json.html_safe %>;


var options = {
  challenge: new Uint8Array([/* bytes sent from the server */]),
  rpId: "example.com" /* will only work if the current domain
                         is something like foo.example.com */
  userVerification: "preferred",
  timeout: 60000,     // Wait for a minute
  allowCredentials: [
    {
      transports: "usb",
      type: "public-key",
      id: new Uint8Array(26) // actually provided by the server
    },
    {
      transports: "internal",
      type: "public-key",
      id: new Uint8Array(26) // actually provided by the server
    }
  ],
  extensions: {
    uvm: true,  // RP wants to know how the user was verified
    loc: false,
    txAuthSimple: "Could you please verify yourself?"
  }
};

navigator.credentials.get({ "publicKey": options })
    .then(function (credentialInfoAssertion) {
    // send assertion response back to the server
    // to proceed with the control of the credential

    // update the hidden form input then
    form.submit();
}).catch(function (err) {
     console.error(err);
});
var-appId=
var registerRequests=;
var signRequests=;
变量选项={
挑战:新的Uint8Array([/*字节从服务器发送*/]),
rpId:“example.com”/*仅在当前域
有点像foo.example.com*/
用户验证:“首选”,
超时:60000,//请稍等
允许条件:[
{
传输:“usb”,
类型:“公钥”,
id:new-Uint8Array(26)//实际由服务器提供
},
{
运输:“内部”,
类型:“公钥”,
id:new-Uint8Array(26)//实际由服务器提供
}
],
扩展:{
uvm:true,//RP想知道用户是如何被验证的
洛克:错,
txAuthSimple:“你能验证一下你自己吗?”
}
};
navigator.credentials.get({“publicKey”:options})
.then(函数(credentialInfoAssertion){
//将断言响应发送回服务器
//继续控制凭证
//然后更新隐藏的表单输入
表单提交();
}).catch(函数(err){
控制台错误(err);
});
但不清楚如何将U2F属性映射到webauthn属性。我似乎找不到一个具体的例子来说明这一点,但我确信它确实有效,因为GitHub和DropBox都有这个确切的流程——你在桌面web上注册U2F设备,然后NFC设备就可以在本机移动设备上使用了

顺便说一句,我想实现这一点的原因是,在本机移动设备上,用户永远不必离开您的web应用程序,本机NFC界面会呈现出来,它们会神奇地被带回您的web应用程序。我目前拥有的是,如果检测到移动设备,则呈现OTP界面,这要求用户切换到Authy之类的验证器应用程序,然后复制OTP并返回移动web。只要拔出钥匙按一下就好了

谢谢你的帮助,
Kevin

使用navigator.credentials.get()时,请确保在调用u2f.register期间设置扩展名:{appid:u2f_appid},即u2f appid参数。在我的例子中,我使用origins.json trustedfacet列表URL


您需要设置extensions.appid参数的原因是,如果WebAuthn rpId失败,则在调用
navigator.credentials.get()
时,它将使用extensions.appid参数返回到较旧的U2F。在2FA场景中,最重要的是
allowedCredentials
数组。这是属于相关用户的凭证ID列表(可能映射到您的
密钥\u句柄
)。我相信(没有个人经验)在U2F迁移场景中,另一个重要的部分是
rpId
,它应该设置为注册密钥所依据的原始主机名。