Secure authentication with FIDO2
Replacements
Moving away from passwords to improve account security is a recurring theme for administrators and security researchers. On the Internet, the password as a knowledge-based factor of authentication still dominates the login methods of online services. Password managers are increasingly relieving the burden on users as a weak point in password selection. However, despite all technical support, many users still use passwords that are easy to remember and therefore easy to crack. Projects like Have I Been Pwned [1] or the researchers of the University of Bonn in their EIDI (effective information after a digital identity theft) project [2] follow a reactive approach to account security; web development needs to focus more strongly on alternative authentication methods.
Back in December 2014, the FIDO Alliance published the FIDO Universal Authentication Framework (FIDO UAF) standard, which was intended to enable passwordless authentication. Since the release of the FIDO2 standard with the Web Authentication (WebAuthn) and the Client to Authenticator Protocol (CTAP) components [3], all the major browsers have gradually introduced support for the Web Authentication JavaScript API and the use of security tokens over CTAP.
FIDO2 Functionality
Fortunately, FIDO2 is very straightforward and, although it mainly uses cryptographic keys, quite easy to understand. Before you can log in to a web service as a user, you first need to go through a registration process. During this process, you generate the cryptographic key material – a public and a private key – on a secure device known as the authenticator. The public key is transmitted later to the application server for authentication. The key is stored there and linked to your user account. The private key remains securely stored on the authenticator, which can be an external device or the trusted platform module (TPM) chip in your computer.
Logging in to a web service (Relying Party) works like this: The web application (Relying Party Application) is executed in your web browser. The server sends a challenge to your browser, which the browser signs with your private key and returns to the web service. The browser functions for FIDO authentication are accessed from within the application by the Java Script API.
Depending on the device you used to register key generation, your browser accesses your computer's TPM chip through the operating system or an external authenticator over the CTAP protocol.
The authenticator has your private key and needs to generate the signature for the challenge. The process often involves entering a PIN or presenting a biometric feature such as a fingerprint. On local devices, passwordless authentication with biometrics works without problem. The authenticator returns the signed challenge to the browser, which passes it on to the application server. The server in turn verifies the signature with the stored public key. If it is valid, the login is completed successfully.
The crucial difference with this approach is that you do not need a certificate authority (CA) to verify the user's identity and then issue a certificate. The identity of the user is not the main focus of FIDO, which is also true of password-based authentication. Instead, the aim is to recognize a user reliably, which means you can also use FIDO for secure authentication of what are basically anonymous user accounts. Also, the use of several, and even different, keys is supported. FIDO2 even lets you as a provider prescribe and verify the type of devices used as authenticators. In the course of certification, a model key pair is generated that can also be integrated into the signature process. In this way, you as a provider can ensure that your customers use certain device classes, such as devices that can only be unlocked with a PIN or fingerprint. The model key pair is then installed on all devices of a certain model (i.e., it is model-specific, but not unique to a device).
Trusted Authenticator
To sign the challenge from the application server, you need another device, known as the authenticator, which can be an internal device, the TPM in your computer, or an external device, such as a USB security token like a YubiKey. Android has had FIDO2 certification since February 2019. Therefore, on devices with suitable hardware and Android 7 or higher, you always have an internal authenticator in your pocket. You can unlock it with your fingerprint or the screen lock PIN. For communication with the security token, FIDO defines the CTAP1 and CTAP2 Client to Authenticator protocols; version 1 is also known as Universal-2nd-Factor (U2F) and version 2 as FIDO2 or WebAuthn. For test purposes in this article, I use a YubiKey NFC (near-field communication) stick, version 5, and a fairly new Android smartphone. The YubiKey is directly detected on Linux as Yubico YubiKey OTP+FIDO+CCID , which you can reveal with the command
sudo dmesg -w
by watching the kernel output when plugging in the key. You can then go to the WebAuthn demo page [4] for initial testing. If the authenticator works with your browser, the next step is to try FIDO2 on your own web page.
Creating the Server Application
To test the following examples, I will use the PHP WebAuthn library by Lukas Buchs [5]. If you already use a PHP-enabled server, you can provide the sample application directly in the WebAuthn _test
folder and deliver the page. Without an appropriate environment, Docker Compose lets you set up NGINX with PHP quickly and easily (Listing 1).
Listing 1
docker-compose.yaml
web: image: nginx:latest ports: - "8080:80" volumes: - ./WebAuthn:/usr/share/nginx/html/WebAuthn - ./default.conf:/etc/nginx/conf.d/ default.conf left: - php php: image: php:fpm volumes: - ./WebAuthn:/var/www/html/WebAuthn
The NGINX configuration requires the default.conf
file (Listing 2), which configures forwarding to the PHP-FPM server for all files ending in .php
. Because the client.html
file, which is delivered as a static page, is located in the same folder as the server.php
file, the same folder is included in both containers in docker-compose.yaml
.
Listing 2
default.conf
server { index index.php index.html; server_name php-docker.local; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; root /code; location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }
You can now start the two Docker containers:
docker-compose up
If you then call http://localhost:8080/WebAuthn/_test/client.html
in your browser, you will be redirected to a secure HTTPS page, although this connection will fail. The redirection is defined in the WebAuthn client.html
file. For this test, it is not necessary, however. Just remove the JavaScript statement that starts with window.onload
in client.html
(lines 246-253). Afterward, you will probably have to clear the browser cache to avoid being redirected.
You can now access the test application website with the URL mentioned above. When you get there, you can access your browser's WebAuthn API by pressing New Registration and proceed to register the existing security token. If you want to test the application from your smartphone, you need to install a valid SSL certificate. On Android, you could otherwise receive a message that the browser is not compatible.
Buy this article as PDF
(incl. VAT)