使用硬件令牌的 2FA 与 WebAuthn API

为了为登录提供更高的安全性,网站正在部署双因素身份验证 (2FA),通常使用智能手机应用程序或短信。这些机制使 网络钓鱼 更难,但无法完全阻止它 - 用户仍然可能被诱骗传递代码,短信也可以通过多种方式被拦截。

Firefox 60 将默认启用 WebAuthn API,提供基于 公钥加密 的双因素身份验证,不受我们今天所知的网络钓鱼的影响。继续阅读以获取介绍,并了解如何保护数百万已经拥有 FIDO U2F USB 令牌 的用户。

创建新凭据

让我们从一个简单的例子开始:这请求一个与标准 USB 连接的 FIDO U2F 设备兼容的新凭据;有许多此类兼容令牌以 Yubikey、U2F Zero 等名称出售

const cose_alg_ECDSA_w_SHA256 = -7;

/* The challenge must be produced by the server */
let challenge = new Uint8Array([21,31,105 /* 29 more random bytes generated by the server */]);
let pubKeyCredParams = [{
  type: "public-key",
  alg: cose_alg_ECDSA_w_SHA256
}];
let rp = {
  name: "Test Website"
};
let user = {
  name: "Firefox User <firefox@example.com>",
  displayName: "Firefox User",
  id: new TextEncoder("utf-8").encode("firefox@example.com")
};

let publicKey = {challenge, pubKeyCredParams, rp, user};
navigator.credentials.create({publicKey})
  .then(decodeCredential);

对于 USB U2F 令牌,这将使连接到用户系统的所有兼容令牌等待用户交互。一旦用户触碰任何设备,它就会生成一个新凭据,并且 Promise 解析。

用户定义的函数 decodeCredential() 将解码响应以接收密钥句柄,无论是存储在设备上的 ECDSA 密钥对的句柄,还是用一个秘密的、设备特定的密钥加密的 ECDSA 密钥对本身。属于该对的公钥以明文形式发送。

密钥句柄、公钥和签名必须通过后端使用随机挑战进行验证。由于凭据与请求它的网站进行加密绑定,因此如果来源不匹配,此步骤将失败。这防止了为其他网站生成的凭据的重复使用。

密钥句柄和公钥将从现在起与当前用户相关联。WebAuthn API 规定没有浏览器 UI,这意味着网站有责任向用户发出信号,让他们现在连接并注册令牌。

获取现有凭据的断言

下次用户登录网站时,他们将需要证明拥有在上一节中创建凭据的第二个因素。后端将检索密钥句柄并将其与一个新的挑战一起发送给用户。由于 allowCredentials 是一个数组,因此它允许发送多个令牌,如果多个令牌与单个用户帐户注册。

/* The challenge must be produced by the server */
let challenge = new Uint8Array([42,42,33 /* 29 more random bytes generated by the server */]);
let key = new Uint8Array(/* … retrieve key handle … */);

let allowCredentials = [{
  type: "public-key",
  id: key,
  transports: ["usb"]
}];

let publicKey = {challenge, allowCredentials};

navigator.credentials.get({publicKey})
  .then(decodeAssertion);

同样,所有连接的 USB U2F 令牌将等待用户交互。当用户触碰令牌时,它将尝试使用给定的 ID 查找存储的密钥句柄,或者尝试使用内部密钥将其解密。成功后,它将返回一个签名。否则,身份验证流程将中止,网站需要重新尝试。

解码后,用于签名的签名和密钥句柄将发送到后端。如果与密钥句柄一起存储的公钥能够使用提供的挑战验证给定的签名,则断言被认为有效,用户将被登录。

第一因素身份验证

Web 身份验证还定义了无需用户名和密码即可使用安全令牌登录的机制,例如智能手机上的受信任执行环境。在这种模式下,您的令牌会证明您不仅拥有它,而且您作为一个人使用密码 (您知道的东西) 和/或生物识别 (您是谁) 解锁了令牌。

在这个世界里,网站可以让你注册,通过在你的智能手机上出现提示并回答提示来执行对桌面上的 Web 应用程序的无缝身份验证。

今天部署的 FIDO U2F 令牌还不够复杂,无法实现这一点,但下一代令牌将可以实现,Web 开发人员将使用 Web 身份验证与这些 FIDO 2.0 令牌进行交互。

WebAuthn,即将在您的 Firefox 附近推出

这是对 Web 身份验证世界的简短介绍,它有意省略了很多细节,例如 CBOR 编码COSE_Key 格式,以及可以传递给 .create().get() 函数的其他参数。

我们鼓励开发人员开始尝试使用 WebAuthn,并允许用户使用第二个因素来保护其登录,因为 API 变得可用。在撰写本文时,我们不知道任何 WebAuthn-U2F polyfill 库,但希望这些库很快可用。如果您看到了一些有希望的东西,请在评论中告诉我们。

将标准化的双因素身份验证带到 Web 上非常令人兴奋;公钥加密已经通过 TLS 协议保护了我们数据在互联网上的传输,现在我们可以使用它来使网络钓鱼变得更加困难。在 Firefox Nightly 中试用 WebAuthn!

USB WebAuthn tokens lit up asking for user interaction

关于测试的最后说明

Web 身份验证是一项强大的功能。因此,它只能在 安全上下文 中使用,如果在框架中使用,则只有当所有框架与父文档来自同一来源时才可以使用。这意味着当您在一些流行的测试网站(如 jsfiddle.net)上尝试使用它时,您可能会遇到安全错误。

关于 J.C. Jones

让人们在网络上安全。Firefox 的密码工程主管。

更多 J.C. Jones 的文章…

关于 Tim Taubert

从事 Firefox 和 NSS 的安全工程师。

更多 Tim Taubert 的文章…


9条评论

  1. T

    完全不清楚服务器上运行什么,客户端上运行什么。
    您能提供一个完整的示例,包括两端吗?

    2018 年 1 月 17 日 凌晨 4:33

    1. J.C. Jones

      抱歉造成混淆!至于完整的开源实现,我们知道 google/webauthndemo,但它似乎还没有完全赶上规范的最新状态,因此它在 Firefox 中尚无法使用。看起来有一些活动正在发生,不过。当您运行代码时,该存储库也是客户端/服务器责任划分的一个很好的例子,即使代码还没有完成。

      2018 年 1 月 17 日 上午 6:27

  2. Eli F.

    Duo Lab 的演示应用程序在这里:https://github.com/duo-labs/webauthn#webauthn-demo
    我不能说它在多大程度上实现了规范,但它看起来对于探索很有用。

    2018 年 1 月 22 日 上午 5:24

  3. desar

    这篇博文中的示例代码不是很有帮助。
    W3C 草案已经包含示例代码。查看第 12 章。
    http://www.w3.org/TR/webauthn/

    您获得了凭据,那么呢。您需要检查/验证它。
    W3C 草案没有示例代码,但它有规范。
    如果您有时间,您应该查看一下。

    查看 webauthn.bin.coffee 以获取有关如何验证的示例
    客户端(浏览器)上的凭据。在客户端进行检查
    不是理想的,这只是一个 POC/示例,当然。
    https://webauthn.bin.coffee/
    https://github.com/jcjones/webauthn.bin.coffee

    规范不仅仅是 U2F,但当前示例都集中于此。
    因为安全密钥很容易获得/制作。

    对于客户端服务器实现,供应商正在开发自己的专有代码,我猜。
    但是,Duo Lab 上面的示例值得查看。希望开源社区对此进行更多努力
    以取得成功。

    顺便说一句,如果有人感兴趣,Chrome 今天也有了工作 beta 版。
    https://groups.google.com/a/fidoalliance.org/forum/#!topic/fido-dev/GH7AahxrE8o

    http://webauthndemo.appspot.com/

    2018 年 1 月 24 日 下午 5:25

    1. kaiju

      我撰写了 Duo Labs 的博文和代码库。如果您对服务器端代码的工作方式有任何疑问,请随时通过 https://twitter.com/codekaiju 与我联系。

      您也可以在 https://webauthn.io 上查看仓库的生产代码。

      2018 年 1 月 31 日 下午 2:39

  4. James Ahern

    感谢您撰写这篇文章。我相信 Mozilla 将在 Firefox 60 中发布它。security.webauth.webauthn 标志会保留吗?或者它默认情况下会为真吗?

    2018 年 1 月 30 日 上午 7:45

    1. J.C. Jones

      标志会保留,但默认情况下设置为 true。谢谢!

      2018 年 1 月 30 日 上午 8:46

      1. James Ahern

        非常感谢您抽出时间回复。谢谢,James

        2018 年 1 月 31 日 上午 8:50

  5. Wellington Torrejais da Silva

    不错,非常有用。

    2018 年 2 月 9 日 上午 7:58

本文评论已关闭。