mirror of
https://github.com/QubesOS/qubes-doc.git
synced 2024-12-29 01:06:24 -05:00
209 lines
10 KiB
Markdown
209 lines
10 KiB
Markdown
---
|
|
layout: doc
|
|
title: The Qubes U2F Proxy
|
|
permalink: /doc/u2f-proxy/
|
|
---
|
|
|
|
# The Qubes U2F Proxy
|
|
|
|
The [Qubes U2F Proxy] is a secure proxy intended
|
|
to make use of U2F two-factor authentication devices with web browsers without
|
|
exposing the browser to the full USB stack, not unlike the [USB keyboard and
|
|
mouse proxies][USB] implemented in Qubes.
|
|
|
|
## What is U2F?
|
|
|
|
[U2F], which stands for "Universal 2nd Factor", is a framework for
|
|
authentication using hardware devices (U2F tokens) as "second factors", i.e.
|
|
*what you have* as opposed to *what you know*, like a passphrase. This
|
|
additional control provides [good protection][krebs] in cases in which the
|
|
passphrase is stolen (e.g. by phishing or keylogging). While passphrase
|
|
compromise may not be obvious to the user, a physical device that cannot be
|
|
duplicated must be stolen to be used outside of the owner's control.
|
|
Nonetheless, it is important to note at the outset that U2F cannot guarantee
|
|
security when the host system is compromised (e.g. a malware-infected operating
|
|
system under an adversary's control).
|
|
|
|
The U2F specification defines protocols for multiple layers from USB to the
|
|
browser API, and the whole stack is intended to be used with web applications
|
|
(most commonly websites) in browsers. In most cases, tokens are USB dongles.
|
|
The protocol is very simple, allowing the devices to store very little state
|
|
inside (so the tokens may be reasonably cheap) while simultaneously
|
|
authenticating a virtually unlimited number of services (so each person needs
|
|
only one token, not one token per application). The user interface is usually
|
|
limited to a single LED and a button that is pressed to confirm each
|
|
transaction, so the devices themselves are also easy to use.
|
|
|
|
Currently, the most common form of two-step authentication consists of a numeric
|
|
code that the user manually types into a web application. These codes are
|
|
typically generated by an app on the user's smartphone or sent via SMS. By now,
|
|
it is well-known that this form of two-step authentication is vulnerable to
|
|
phishing and man-in-the-middle attacks due to the fact that the application
|
|
requesting the two-step authentication code is typically not itself
|
|
authenticated by the user. (In other words, users can accidentally give their
|
|
codes to attackers because they do not always know who is really requesting the
|
|
code.) In the U2F model, by contrast, the browser ensures that the token
|
|
receives valid information about the web application requesting authentication,
|
|
so the token knows which application it is authenticating (for details, see
|
|
[here][u2f-details]). Nonetheless, [some attacks are still possible][wired] even
|
|
with U2F (more on this below).
|
|
|
|
## The Qubes approach to U2F
|
|
|
|
In a conventional setup, web browsers and the USB stack (to which the U2F token
|
|
is connected) are all running in the same monolithic OS. Since the U2F model
|
|
assumes that the browser is trustworthy, any browser in the OS is able to access
|
|
any key stored on the U2F token. The user has no way to know which keys have
|
|
been accessed by which browsers for which services. If any of the browsers are
|
|
compromised, it should be assumed that all of the token's keys have been
|
|
compromised. (This problem can be mitigated, however, if the U2F device has a
|
|
special display to show the user what's being authenticated.) Moreover, since
|
|
the USB stack is in the same monolithic OS, the system is vulnerable to attacks
|
|
like [BadUSB].
|
|
|
|
In Qubes OS, by contrast, it is possible to securely compartmentalise the
|
|
browser in one qube and the USB stack in another so that they are always kept
|
|
separate from each other. The Qubes U2F Proxy then allows the token connected to
|
|
the USB stack in one qube to communicate with the browser in a separate qube. We
|
|
operate under the assumption that the USB stack is untrusted from the point of
|
|
view of the browser and also that the browser is not to be trusted blindly by
|
|
the token. Therefore, the token is never in the same qube as the browser. Our
|
|
proxy forwards only the data necessary to actually perform the authentication,
|
|
leaving all unnecessary data out, so it won't become a vector of attack. This is
|
|
depicted in the diagram below (click for full size).
|
|
|
|
[![Qubes U2F Proxy diagram](/attachment/wiki/posts/u2f.svg)](/attachment/wiki/posts/u2f.svg)
|
|
|
|
The Qubes U2F Proxy has two parts: the frontend and the backend. The frontend
|
|
runs in the same qube as the browser and presents a fake USB-like HID device
|
|
using `uhid`. The backend runs in `sys-usb` and behaves like a browser. This is
|
|
done using the `u2flib_host` reference library. All of our code was written in
|
|
Python. The standard [qrexec] policy is responsible for directing calls to the
|
|
appropriate domains.
|
|
|
|
The `vault` qube with a dashed line in the bottom portion of the diagram depicts
|
|
future work in which we plan to implement the Qubes U2F Proxy with a software
|
|
token in an isolated qube rather than a physical hardware token. This is similar
|
|
to the manner in which [Split GPG] allows us to emulate the smart card model
|
|
without physical smart cards.
|
|
|
|
One very important assumption of U2F is that the browser verifies every request
|
|
sent to the U2F token --- in particular, that the web application sending an
|
|
authentication request matches the application that would be authenticated by
|
|
answering that request (in order to prevent, e.g., a phishing site from sending
|
|
an authentication request for your bank's site). With the WebUSB feature in
|
|
Chrome, however, a malicious website can [bypass][wired] this safeguard by
|
|
connecting directly to the token instead of using the browser's U2F API.
|
|
|
|
The Qubes U2F Proxy also prevents this class of attacks by implementing an
|
|
additional verification layer. This verification layer allows you to enforce,
|
|
for example, that the web browser in your `twitter` qube can only access the U2F
|
|
key associated with `https://twitter.com`. This means that if anything in your
|
|
`twitter` qube were compromised --- the browser or even the OS itself --- it
|
|
would still not be able to access the U2F keys on your token for any other
|
|
websites or services, like your email and bank accounts. This is another
|
|
significant security advantage over monolithic systems. (For details and
|
|
instructions, see the [Advanced usage] section below.)
|
|
|
|
For even more protection, you can combine this with the [Qubes firewall] to
|
|
ensure, for example, that the browser in your `banking` qube accesses only one
|
|
website (your bank's website). By configuring the Qubes firewall to prevent your
|
|
`banking` qube from accessing any other websites, you reduce the risk of another
|
|
website compromising the browser in an attempt to bypass U2F authentication.
|
|
|
|
## Installation
|
|
|
|
These instructions assume that there is a `sys-usb` qube that holds the USB
|
|
stack, which is the default configuration in most Qubes OS installations.
|
|
|
|
In dom0:
|
|
|
|
```
|
|
$ sudo qubes-dom0-update qubes-u2f-dom0
|
|
$ qvm-service --enable work qubes-u2f-proxy
|
|
```
|
|
|
|
In Fedora TemplateVMs:
|
|
|
|
```
|
|
$ sudo dnf install qubes-u2f
|
|
```
|
|
|
|
In Debian TemplateVMs:
|
|
|
|
```
|
|
$ sudo apt install qubes-u2f
|
|
```
|
|
|
|
Repeat `qvm-service --enable` (or do this in VM settings -> Services in the Qube
|
|
Manager) for all qubes that should have the proxy enabled. As usual with
|
|
software updates, shut down the templates after installation, then restart
|
|
`sys-usb` and all qubes that use the proxy. After that, you may use your U2F
|
|
token (but see [Browser support] below).
|
|
|
|
## Advanced usage: per-qube key access
|
|
|
|
If you are using Qubes 4.0, you can further compartmentalise your U2F keys by
|
|
restricting each qube's access to specific keys. For example, you could make it
|
|
so that your `twitter` qube (and, therefore, all web browsers in your `twitter`
|
|
qube) can access only the key on your U2F token for `https://twitter.com`,
|
|
regardless of whether any of the web browsers in your `twitter` qube or the
|
|
`twitter` qube itself are compromised. If your `twitter` qube makes an
|
|
authentication request for your bank website, it will be denied at the Qubes
|
|
policy level.
|
|
|
|
To enable this, create a file in dom0 named
|
|
`/etc/qubes-rpc/policy/policy.RegisterArgument+u2f.Authenticate` with the
|
|
following content:
|
|
|
|
```
|
|
sys-usb @anyvm allow,target=dom0
|
|
```
|
|
|
|
Next, empty the contents of `/etc/qubes-rpc/policy/u2f.Authenticate` so that it
|
|
is a blank file. Do not delete the file itself. (If you do, the default file
|
|
will be recreated the next time you update, so it will no longer be empty.)
|
|
Finally, follow your web application's instructions to enroll your token and use
|
|
it as usual. (This enrollment process depends on the web application and is in
|
|
no way specific to Qubes U2F.)
|
|
|
|
The default model is to allow a qube to access all and only the keys that were
|
|
enrolled by that qube. For example, if your `banking` qube enrolls your banking
|
|
key, and your `twitter` qube enrolls your Twitter key, then your `banking` qube
|
|
will have access to your banking key but not your Twitter key, and your
|
|
`twitter` qube will have access to your Twitter key but not your banking key.
|
|
|
|
## TemplateVM and browser support
|
|
|
|
The large number of possible combinations of
|
|
TemplateVM (Fedora 27, 28; Debian 8, 9) and browser (multiple Google Chrome
|
|
versions, multiple Chromium versions, multiple Firefox versions) made it
|
|
impractical for us to test every combination that users are likely to attempt
|
|
with the Qubes U2F Proxy. In some cases, you may be the first person to try a
|
|
particular combination. Consequently (and as with any new feature), users will
|
|
inevitably encounter bugs. We ask for your patience and understanding in this
|
|
regard. As always, please [report any bugs you encounter].
|
|
|
|
Please note that, in Firefox before Quantum (e.g. Firefox 52 in Debian 9), you
|
|
have to install the [U2F Support Add-on][ff-u2f-addon]. In Firefox post-Quantum
|
|
you may have to enable the `security.webauth.u2f` flag in `about:config`. Chrome
|
|
and Chromium do not require any special browser extensions.
|
|
|
|
|
|
[Qubes U2F Proxy]: https://github.com/QubesOS/qubes-app-u2f
|
|
[USB]: /doc/usb/
|
|
[U2F]: https://en.wikipedia.org/wiki/U2F
|
|
[krebs]: https://krebsonsecurity.com/2018/07/google-security-keys-neutralized-employee-phishing/
|
|
[u2f-details]: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-overview-v1.2-ps-20170411.html#site-specific-public-private-key-pairs
|
|
[wired]: https://www.wired.com/story/chrome-yubikey-phishing-webusb/
|
|
[BadUSB]: https://www.blackhat.com/us-14/briefings.html#badusb-on-accessories-that-turn-evil
|
|
[qrexec]: /doc/qrexec3/
|
|
[Split GPG]: /doc/split-gpg/
|
|
[Qubes firewall]: /doc/firewall/
|
|
[Advanced usage]: #advanced-usage-per-qube-key-access
|
|
[Browser support]: #templatevm-and-browser-support
|
|
[report any bugs you encounter]: /doc/reporting-bugs/
|
|
[ff-u2f-addon]: https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/?src=api
|
|
[qubes-devel]: /support/#qubes-devel
|
|
|