Building secure web experiences with Passwordless Authentication
(upbeat electronic music) (audience applauds) - Hey everyone.
So, for part of my day job I work remote applications and one of the things I'm always concerned about is security, like most of you would be.
So, quite recently, there's been support in web browsers to actually enable passwordless authentication, and that's what I want to talk to you today. But firstly, let's talk about why passwords are a problem. So, Yubico which is a major supplier of security keys, surveyed over 1,500 IT professionals, some who are actually working in security as well. And basically just asked them about their security practises and how they do things on a day-to-day job. I'm going to show you some stats that might actually shock you.
69% of these professionals admitted to actually sharing some sort of passwords with colleagues.
Put your hand up if you've done that for any reason. I'm getting a lot of nods.
Like, yeah, I'm sure it'd be a lot more, but people are just try to hide their dignity. (laughing) (crowd laughing) So, that's quite a large number.
It gets worse.
67% admitted that they have never used two-factor authentication in their personal life, their banking or whatever.
And that's actually 55% for those who don't use it out of the workplace.
51% of these respondents have said they've actually experienced a phishing attack, that they've lost their identity or the credentials or some sort of information based on their profiles.
And that's actually 44% in the workplace.
Despite all of this, and perhaps most alarmingly, 57% of respondents said they were not gonna change their password practises based on this.
This is crazy, 'cause say you show that most users tend to have about 90 accounts on the web these days considering how ubiquitous a lot of services are. So, let's look at how we can actually try and solve this problem.
And, the way we can actually solve this problem is using something called WebAuthn, or web authentication for short.
So, 'cause everything has to sound cool these days. So, what is WebAuthn? Essentially it is a new W3C web standard that got ratified this year with a lot of major players like Google and Microsoft.
Where it aims to actually improve web security essentially by using public key cryptography. Where do we use public key cryptography? When using HTTPS, so through your SSL certs and the like. That's using essentially private keys on the server to encrypt stuff and you have a public key to verify that's from the server that you're talking to. And we can essentially use this same practise for using this on devices and communicate to applications. So, how does it work? The first part of this framework is that we have an authenticator of some sorts. So, the real benefit of this API is, essentially, it's abstracted what an authenticator is.
So, you could have something that's like a security key, you could have something that's biometric, such as your fingerprint or your iris scan and so forth on a phone.
You can actually use your phone itself as a device, or your desktop.
There's a lot of different ways you could actually act as an authenticator.
These authenticators connect to the client, in this case for this API, you're connecting with a web browser and usually you have a user actually do some sort of input to verify that they want to use an authenticator of some sorts.
And then, that connects to a relying party, or a server in this case.
So, we have the client talk to the server, it might be an identity provider, so you might be looking at something like Auth0, Okta or Google.
And essentially just passing credentials through the authenticator and then verifying who you are, essentially.
But enough talking, I want to show you a quick demo. Essentially, of how this actually works in practise. I've actually pre-recorded this, 'cause that way I don't have to stuff around with hardware keys and all that.
But, that way you can just get an understanding of how it works.
So, here I'm just gonna put in a username, 'cause I don't wanna have any passwords involved at all, and gonna try and register a credential.
So, I'm using Google Chrome.
That gives me an option to use USB security key, or built-in sensor.
So, here I've looked at user security key I plug it in, and with these security keys you actually have to touch the sensory authenticator that you want to use that credential.
So, I've done that.
The application's requested that I want to use a security key, and I've said yes, I've permitted that.
And then the application's gone, "It's all good." And once I press it.
So very simple sort of process.
Very minimal amount of code.
The complicated part is, essentially, the server aspect.
So, that's USB security key, essentially.
Let's get into something a bit more cooler. Well, so this time we're try and register a credential, and on my MacBook I've got the actual touch ID mechanism, so I can actually use my fingerprint to actually store stuff.
So, here I'm going to request use of built-in sensor, in this case, the fingerprint.
That's me, essentially, this credential using that. The application asked me do I wanna allow this credential and so forth, and then it's been registered for that.
Then when I try to log in using the same username, I can just use my fingerprint on that.
So, very cool, and also it has some drawbacks doing that as well, which I'll get into a bit later. So, that was really quick and simple.
What are the key benefits? It's an industry standard, so we're getting a lot of major backing for a lot of major browsers.
It's passwordless, you saw no mention of any types of passwords or anything like that. Having said that, you could also use this mechanism from a two-factor authentication point of view. So you do have that benefit if you don't want to ditch passwords at all.
It is much more seamless user experience.
So, you saw the registration's quite simple, so you could have your own work flow, depending what the application is.
Well, actually the process of authenticating would be incredibly fast.
Especially if you're using something like a phone, and you got your fingerprint on stand-by or using your eye scan or so forth.
And one of the real benefits of this API is essentially, it's been secure by design.
So, it was being discussed for quite a while through the working group, and they're still actually looking at improving version two, that should be coming out in the next year or so. Essentially, the reason this is secure is that these private keys that we're using to encrypt this credentials never leave the browser. In the case of the security key, the private key is actually stored in the security itself. If you look at something like a fingerprint, the actual key itself is being stored on the operating system using a secure enclave of some sorts.
So this can actually help increase trust in users actually using these applications. 'Cause that way they don't have to transfer their password, they can just use something that they actually own. So, let's go into a bit more specifics of how this actually works.
So we'll go through the registration workflow. So, the application itself talks to the relying party, saying, "I want to actually register an account." It then sends back a challenge, essentially saying that for a transaction, you need to make sure this is all good.
So, that way you can send that challenge back later on. We talk to the Authenticator, essentially say, "Hey, we want to create a credential using the "WebAuthN sort of APIs." We then have the Authenticator create and return a new key pair attestation which is, essentially, like proof of what the credential is. The application then sends response back to server, and this is where you can start doing some of your own logic.
Do you write the credentials from other additional data, like what the user name is, what your age is, any of that sort of data, you can essentially put that in and make sure you send it to the server.
Once you do that, the server then validates it, and finalises credential registration.
So, that way the server, essentially, is just storing an ID of the credential that has been used to register.
And when you try and retrieve it later on, it just asks for that ID and works from that. Now, the reason this is a 20-minute talk, and not a two hour talk, is that the front-end side of things within implementing this is quite simple.
But the server validation process is quite complex. The standard itself has about 20 or so steps to actually go, "This is how you validate credentials, "and make sure it's not been compromised." So, it is a lot of libraries are now getting made to essentially help to facilitate the process. So, let's look at some of the code.
So, the actual API call that we use, to actually invoke this API, to a creating credential is navigator credentials create. So, you can easily check this as well to make sure it's actually available in the browser.
So, it's a fair bit of code.
We'll step through it bit by bit.
So, essentially, before you can actually create a credential we need to actually pass some options. So, these options could actually be passed from a server. So, if you look at the first part, we have a challenge. Essentially, this is a unique random string that's been sent back to the server, essentially, to make sure that no one's gonna compromise and try and create credentials on its behalf. 'Cause the server will actually validate that the challenge is the same in the complete transaction. We have rp which just stands for relying party. So this is where we could have additional information about who you're actually connecting with or what your application is.
In this case I've just got a simple name, but you could have an identifier as well.
So, if you've got, like, OAuth sort of type clients, you can actually specify the identity of which application is authorised to use this credential.
You have a user identification.
So, essentially, the idea is what's been generated as a sort of unique ID for the user. So, you don't wanna use anything that's personally identifiable.
Some of this code is gonna be stored on a database of some sorts.
But you can have things like display name and all sorts of stuff allocated for that as well. The public key sort of params.
So these one are quite complex, but, essentially, there's a standard which I mentioned above, which is a cosi standard, which is a bit hard to read on the projector. Essentially, it's a list of algorithms that you can use. So, ES256 is quite common, it's using JWTs and the like. So, essentially, they reference that standard as a negative seven, so I've referenced that. And saying that the type is public-key.
So the essential WebAthn API plugs into a existing sort of credential API system.
So, where there was existing support for USB keys, but this one essentially just abstracts authenticators, and makes it a lot easier to have a lot of different sort of devices used.
Here I actually specify what type of authenticator selection I want.
So, there's this notion of cross-platform and platform-specific authenticators.
So, I mentioned before there's bit of a gotcha if you actually use fingerprints and the like. The reason USB keys are cross-platform is that the private key's actually stored on the security key itself.
So I can essentially plug that into my laptop and it works, and I could plug it into another computer and it'd be the same credential because it's stored on that device.
My fingerprint, though, is going to get written on that device.
Even though it's my fingerprint and it's not gonna be duplicated, unless I'm a clone or something, if I try and use that on a phone, even though it's the same fingerprint, it's gonna actually have a different credential created to represent that fingerprint.
So that's a platform-specific credential.
Another one of these is something like Windows Hello, where you're actually using your face to actually log in to the application and so forth. We specify a timeout.
So, to make sure that we're not essentially having the user wait for too long, but also it's the security thing to make sure that you're not gonna have an hour for someone to register their credential.
Someone had to run off to the toilet and someone else puts credential in.
Helps prevent that.
And you can also ask for how much information you want about the authorizer itself.
So for the security key I demonstrated just before. You can actually go, "I want to know it's a Yubico "authenticator with this particular certificate "and so forth." You can ask for that sort of information.
You can also elect to not ask for that information, if you just want to anonymise it because you don't care. You just want a credential to be essentially used to sign as well.
Once that's all done, we can essentially wrap all those options and paste it into this.
So we just create those credentials and we essentially have a promise return and authenticator attestation response.
So we can have essential public-key credential return. So the id essentially is a base 64 string, You know, it's in, sort of, hexadecimal there, to represent the rawID, which is the binary string, which is what the credential is actually represented as. Is identifiable.
And that gets sent to the server for verification and also retrieving credentials later on.
So we've got also the response.
So the response, the actual client data that was sent, it gets wrapped up in this sort of package. But it also gets signed as well for this attestation object. That way the server can actually validate that the entire payload is signed by the private key. And gets provided a public key for this response as well. So the authentication workflow is very similar. We saw how an application talked to the server's request for authentication.
The server sends another challenge.
We then talk to the authenticator through the browser. The authenticator then creates and returns an assertion, saying that this is the credential that was requested.
So this is going for a successful flow.
See, if the server request a credential id that doesn't exist, the browser would go, "I don't know what that is." Essentially.
The application then sends a response back to the server. And then we can actually get authenticated if everything's all well and true.
So let's just now look at the second part of the API, which is getting the credential.
So very similar sort of pattern.
We still need to set up some options to actually provide to get the credentials.
So we still need to contain the challenge that's sent from the server, to make sure the transaction's the same one that we want. We then specify what the id is.
This is the credential id that gets generated in the previous step.
We've set that at public-key.
But the server can also restrict what kind of credentials are used.
So you could actually go, "Hey, I actually want anything "that's USB or blu-tooth or NFC tags." You can restrict it that way.
Otherwise, some servers just might not care. Again, we have the timeout.
And then, once that's all well and done, we just pass that through the options and we get our credential created.
So that's what that looks like.
Again, same sort of response sort of type.
We still have an identifier for the actual credential. With the rawID, which is a binary string with an array buffer for that.
We then get the response.
So, essentially, we have the signature getting created across all these sort of paths. The user handle is optional.
But you can essentially use that to add scopes and the likes.
That way you can have the server verify that, yes, this user is an admin with a public key, and verify them through that way.
But, essentially, it's a very simple sort of process. The real sort of crux of using this API is the server and actually having that validate the credentials and make it work.
So, some of the design considerations if you actually want to use WebAuthn today. So, we have this problem with the cross-platform and platform-specific credentials, using authorizers. I find the, my main concern with this is more from a UX point of view.
If you go in the application going, "Hey, you can use your fingerprint to sign up "rather than using a password!" People aren't going to know that, "Hey, my fingerprint's only going to work on one device." So I think there's gonna need to be some education or some sort of user hold-handing, at least in a workflow to actually help support that. But what happens if I cut my finger off accidentally? So, you have to be aware that you can't just use one authorizer for an application as well.
So you might need to actually enforce multiple authorizers. Like, if you're having security keys, tell them, "Hey, use one, then use another one, "then throw that away and store it in a safe place." Alternatively, you need to essentially work out what a recovery process will look like for an application. If you're not gonna have passwords, is there some other way that an application can verify who you are? Do you need to ring up or something? It's a very important consideration that you need to make. So, web browser support.
It's really good if you ignore Safari.
So, I've noticed a lot of these web standards lately, that Safari's becoming the new Internet Explorer, where they're usually the last person who implements a standard.
But, interestingly enough, even though it looks all green across the board for, like, Firefox, Chrome, and Edge and so forth, that's more so for just using security keys. If you want to use other modalities like biometrics and the like, I found Chrome has the best support for it. Especially on mobile as well.
I tried to use Firefox mobile to see if I could use fingerprint, and it just didn't work.
It didn't even know there was a fingerprint reader on the device.
So if you're sticking to just security keys for the moment, you're fine.
If you're gonna look at some of the other modalities, you need to be aware of what you need to do. To summarise, you can implement passwordless authentication today, but you do need to be aware that the browser support, while it's sort of starting to get there, and Safari will be supporting it for the next, sort of, operating system release.
That's only for the desktop at the moment, they haven't really stated if iOS is gonna do that. You couldn't get this, sort of, implemented pretty quick today.
A lot of identity providers like Auth0 and Okta and so forth have basically backed this standard, saying that they're gonna be using this forward for this sort of approach.
So even if you're not gonna have your own server doing all this authorization side of things, you can plug into a third party that's gonna do it and do it quite well.
We have the increased security because we don't have to worry about passwords or password management anymore.
So we don't have to have anyone writing passwords, which still happens today.
We have an improved user experience because of this as well. Like, I have the problem where I use accounts that I might have made five years ago, and go, geez, what password did I use then? I wasn't using password managers around then. So, having something like a security key or anything like that will really help increase the user experience.
Especially if you're building an application and you just wanted to have an admin screen and just put a security key behind it without having to worry about a massive database storing credentials and all that.
It's quite an easy way of doing things.
But most importantly, we really need to work out, as developers, what sort of workflow do we have when we're actually integrating this? So, if someone's registering without a password, is that fine? Is it meant to be an account that's a throwaway? Or is it meant to be an account that can be used through time and time again? So, if so, you need to start going, okay, what multiple authorizers could I support? So I still use a password potentially, as a hybrid, and then still have one of these authorizers as a two-factor authentification approach to secure the account a bit more? So that might be the approach if you're trying to do, sort of, migration of some accounts to make sure they've got additional security and they currently don't. Cool.
Um, so, that's it for my presentation.
I hope you really enjoyed it.
(audience applauds) (upbeat electronic music)