PWA and Biometric authentication: a Unikname Journey
Regular users of My Unikname App will be familiar with the process: you open your app and are immediately prompted for your PIN. This is used to authenticate you and be sure that the right person is accessing the app. Some of you have been a little unhappy with this, so goes the constant battle between security and usability. We have had numerous requests to add biometry as an option to authenticate instead. So we have been looking into it. Here is what we found.
The best tool for the job seemed to be the WebAuthn library. Unfortunately, this library can only be used for signatures. When the app is not being used, the data are encrypted. My Unikname App needs to be able to decrypt this data when you authenticate. Webauthn does not directly provide this capability. We have unsuccessfully tried to twist WebAuthn to our needs. The search for the perfect tool is therefore still afoot.
If you need more details, follow along with us, as we recount our journey with in-app biometric authentication.
My Unikname App
Why do you need a PIN?
The first question you might ask is why you need to authenticate to use your app in the first place. Authentication factors are often separated in three categories: what you know (e.g. a password), what you have (e.g. a key), and what you are (e.g. your thumbprint).
Using My Unikname App, you can authenticate to a host of websites thanks to something that you have: your smartphone, or more specifically, your UniknameID and the cryptographic material that goes with it, all of that being safely stored in your app.
But what if your phone is stolen, lost, or simply left unattended next to nefarious individuals? Then they would have what you have, and be able to connect to your favorite websites in your stead. To mitigate this risk, we ask you to authenticate before accessing your app with something that you know: your PIN.
This enhances the security of the solution because now, to login to a website using Unikname Connect, you need to have your phone and to know your PIN. Of course, this is not perfect. PIN, just like passwords, can be forgotten, guessed, shared, etc. So could we substitute it for something that you are, i.e. use biometry?
The right tool for the job?
My Unikname App is not a traditional mobile application, it is a PWA. As such, it relies on web technology to implement new features. WebAuthn is a specification developed by W3C and the FIDO Alliance. It enables user authentication to web-based applications using public-key cryptography and Authenticators.
Authenticators are devices that store private keys. They can either be nomad – think USB key fob – or built into devices – think the fingerprint scanner from your smartphone or laptop. The key never leaves the Authenticator. Instead, messages are fed to Authenticators that sign them locally, and return the signature.
Some Authenticators require the user to perform a specific task before agreeing to sign anything, for instance press a button, or present a valid fingerprint. WebAuthn gives us an API to request these signatures. The process is simple: send a challenge, get a signed response, check the signature!
Though it is the most promising tool at our disposal, WebAuthn has a few issues. First, it is not yet implemented by all browsers, especially not on mobile. Today, it is only available for Chrome for Android and Safari for iOS. But more importantly for us, WebAuthn only does signatures.
Encryption vs Signatures
Let us rewind a little bit to My Unikname App and its PIN-based authentication, and get into what technically happens when you authenticate. When you are not using your app, all of its data is encrypted. This protects your information in case your device is stolen. To decipher your data and make it usable again, we need the decryption key. Where is it stored?
Certainly not on your phone. If it was, whoever would have your phone would also have the key. In the cloud maybe? No, Unikname does not store any sensitive information. In fact, the safest way to store this key, is to not store it at all. Instead, the key is simply re-calculated when needed. And to do that, we use your PIN.
The PIN is derived many times over, using the appropriate cryptographic algorithms, to create a secret key. This key then unlocks all of your data.
So we need your PIN for two separate reasons:
to authenticate you with something that you know,
to decrypt the sensitive data stored on your phone.
Problem is, the WebAuthn API does not offer encryption options. Are we stuck then?
From Signature to Encryption
Hope is not lost yet. To reproduce the process that we currently use with the PIN, we need a reliable piece of data that can consistently be derived into the same key. Can WebAuthn give us that? Well, … kind of. What WebAuthn gives us is the signature of a challenge. It is a piece of data, but is it reliable?
To make the signed challenge consistent we need two things:
a deterministic signature algorithm
a fixed challenge
We can only somewhat control the choice of algorithm. During the registration phase, the Authenticator and the server have to agree on what algorithm to use. This algorithm needs to be implemented on both ends so that the Authenticator can sign the challenge, and the other party can verify the signature.
The server can restrict and even order the list of algorithms the Authenticator can use. But if we choose algorithms that are too exotic, Authenticators are unlikely to know them.
The perfect algorithm is therefore not only deterministic, but also widely implemented. ECDSA seems to be a good candidate for this.
What about our fixed challenge? Challenges are usually randomly generated, with a new challenge being used each time someone tries to authenticate. This is an anti-replay protection. Without it, an attacker can observe one authentication exchange, capture the signed challenge as it transits between the user and the server, and present it later to pose as the user. By specifically requiring the challenge be fixed, we are opening up a possible attack vector in the app.
However, in our setting, this attack scenario is unlikely. Everything happens on your phone. Therefore, there is no communication channel to eavesdrop on. To observe the authentication exchange, the attacker would need a way to spy on your phone itself. And if an attacker can do that, you have bigger problems.
To mitigate the risks even further, we can limit acceptable Authenticators. Remember that Authenticators are either nomad or built-in. Nomad Authenticators have to connect to your phone, thus creating a communication canal to eavesdrop in. Though they usually use short range protocols such as Bluetooth, which would limit the range of such an attack.
By only using build-in Authenticators, we limit the opportunities for a malicious attacker to eavesdrop on the exchange between it and your app. This still leaves us with a lot of authentication methods. Examples of built-in Authenticators include your in-phone fingerprint sensor, your faceID, drawing your pattern, entering your phone’s PIN number, etc.
ECDSA and Determinism
Let us recap our journey. We have a tool, WebAuthn, that looks promising with a few quirks to work out. We have devised a set of restrictions – sticking to built-in Authenticators – to mitigate possible security risks. And we have found an algorithm, ECDSA, that is implemented on most authenticators, including in smartphones, and that can be deterministic.
According to its specification, ECDSA can have both deterministic and non-deterministic implementations. And deterministic implementations are the most popular. Yeah!? Not quite. Deterministic ECDSA includes a number of variants that makes it … non deterministic.
One of them, for instance, adds a signature count to every message signed with a given key. This means that instead of signing ‘Lovely day’, Authenticators would sign ‘Lovely day1’, ‘Lovely day2’, etc. Leading to different signatures.
WebAuthn does not allow us to restrict the use of such variants. The choice to use them or not is left to Authenticators. Unfortunately for us, we have found that built-in smartphone authenticators today use such variants that make ECDSA non deterministic.
Thus we cannot use it to generate our precious key.
In the end, does it work?
No. It doesn’t.
Though promising in theory, ECDSA turned out to be unusable in practice. There are no other widely implemented algorithms that could be good candidates. We are stuck.
But it is not necessarily the end for biometry in My Unikname App! Remember that the PIN is used both for authentication and to decrypt your app’s data. If it cannot be used for the latter, WebAuthn can still enable authenticated actions within the app.
Tomorrow, we could offer an advanced security feature that would require you to re-authenticate before performing sensitive operations: accepting a connection request, sending a blockchain transaction, changing some sensitive settings, who knows. In this case, no decryption is necessary as your app is already open. We can use a vanilla version of the WebAuthn API and offer a large range of authentication options: in-phone fingerprint sensor, bluetooth security keys, face ID on iOS, etc.
Though unsuccessful, this journey taught us valuable things about the PWA ecosystem. The PIN is shaping up to be a tough opponent, but the search continues.