 All right, this is super loud. Give me a second. OK, much better. So thanks for the intro. Yeah, it's true. I am a physicist. I don't admit it too often because then people don't take me seriously, right? Because if you didn't even study computer science, are you a real developer? So yeah, anywho. I'm going to talk about what makes JavaScript Web token secure. And so I think the previous speaker already said this, but when you're building front end applications, there's so many things you have to think about. There's routing performance, animations, keeping up with react cons. So there's a bunch of things you have to do, right? And often security takes a backseat, which is obviously not cool, but it always happens. And there's like multiple methods of securing your applications, right? You can use cookies, tokens. You can handle them differently. You can have no sessions. You can only do a server side. You can use Java stuff, web applets and shit. But the idea that security is difficult, right? It's a tough thing, and it's not super accessible to learn. So I'll talk about one of the popular methods of authentication, which is Java JSON web tokens. I tend to prefer JSON web tokens because they're not super difficult in implementation. It's for non-computer science geeks like me who can understand it, but it's still secure at the same time. So who am I? I'm Siddharth. I work for this company called Auth0. Auth0 is this authentication security company, right? It's like, if you don't have security engineers outsourced it or more like used tools that already do that for you. Tiny pitch. I'm on Twitter. I post garbage stuff all the time. I also run this side company thing. I called frontend army, where I do training mostly frontend stuff, mostly react these days. Cool. Back to JSON web tokens. So JSON web tokens are, I'm just gonna call them JWT, are actually an open standard. So it was built by a few folks from Microsoft and people around them. And the paper is actually open. So you can read the research paper. It's surprisingly short. So you can read it. It's all open there, it's all there. And they kind of built it for a different reason, but it's been repurposed on the web for authentication or I should say authorization. So the first use case that they actually built it for was information exchange. So it's just JWTs are a great way of transmitting information between parties, right? They can be signed. You can use public private key pairs. So the idea there is you're always sure of who sent you this message. If there's a hacker in between you'll probably get to know. And then it's been repurposed for the web for authorization, which is for a logged in user you want to figure out is this actually the user or is this somebody else in between? It's a hacker or it's like tampered data. So should I give access to this route, this service, this API? This is a snapshot of the problem it tries to solve. So have your user, you have your API server. This is the original connection, but sometimes somebody steals the token or somebody is impersonating your user, right? And that's the hacker. Sometimes it's just a man in the middle attack that tampering with your network. And your API server needs to be sure that is this my user or is this someone else? That's the problem that JWT aims to solve. It does that by doing something called stateless sessions. So the idea is that these sessions need not be stored in your database like cookies. It can just live on the client side and get passed around. And this kind of leads to some interesting vulnerabilities and also some interesting features. I'm gonna talk about all of them. But to understand how they're actually secure because if it's on the client side, it's kind of just visible, right? It's like, if it's there, somebody can just do a Chrome extension and just steal it, right? So how does it secure? So to understand that, we need to understand the structure of a JWT. It's three parts. It's the header, the payload and the signature. The header and payload are kind of dumps. They look like this. This is what a token looks like. It's all gibberish hash stuff and I've color coded so that looks pretty on black, but mostly to signify what is the header and what is the payload. Cool. So you can also have JWTs without a signature. It's supported by the spec. It's not useful for security purposes, but it's supported. It exists and we'll talk about it. It's important later. Cool. The header is the metadata about this token. You have, there's only one mandatory field, which is the algorithm. So you say algorithm and these are some of the nicer algorithms. You can use HS256 or RS256 and you can also use none, which is the no security part of it. There are multiple other fields. You can say what is the type, like type is always JWT for us. You can say what is the content type? So the payload, is it a JSON object? Is it again a JWT, like you have nested things? But for the most part of it, this is enough. Cool. And then, so to make that hash thing, you first JSON stringify it and then you base 64 URL encoded, right? This makes it secure for the web. So all of the exclamation, all the positive sign, you hash them down so that you can pass them around. And this is what it looks like, right? Again, it's only encoded. It's not encrypted, which means if somebody has this, they can just base 64 decode and they'll get back the JSON object, right? So they can see your metadata, it's out there. Next is the payload. So payload is the message you're trying to send. So again, it has, it can have any fields you want. These are the canonical fields. So you have the sub, which is usually the subject. And then you have the issuer. Issuer is with service issued this token. It could be your own authentication server. It could be the same API. It could be a third party, like out zero. What is the intended audience for this token? So for example, this token is only useful for the cart API. Any other API that you use it for should reject it. You have the expiry, you have the issued add, both of these are date time. And then you can have any number of custom fields. Like I have name, John Doe and is your admin or not. So that's, I'm going to strip everything else. This is the useful part for my talk. And then you do the same thing. You stringify, encode, you get this ugly hash. Again, it's decoded, not encrypted. If somebody has this, they can decode it and get the thing. So the decode thing is you can only use session information here, don't try to put secret information like a password or a credit card info, right? Because somebody can't decode this. Again, if third parties can read this, why advise this even a good authorization mechanism? And that's where we have the signature. That's the most interesting part. So to create a signature, you need the header. You need the payload. You need a shared secret for HS256 and you need the algorithm that you're using. So it's a function of all of these. The secret is the most important part. So it's not your password that you use for your Gmail account or stuff. It has to be more, it has to have more entropy. So the recommended thing is use a 256 bit secret like this. And you obviously don't hard code it. So I'm going to read it from the process here. I'm going to store it as an environment variable so that accidentally it doesn't get committed to GitHub. It sounds silly to say this, but it has happened in the past with people and companies have gone down because of it. So, yes, we'll mention. And to create a signature, you can use the crypto library. It's a built-in. Crypto here stands for cryptography, not cryptocurrency. So, just the side that I have to mention it. So as you can use crypto library, you can create a HMAC with the HMAC stands for hashing for message authentication. And then you can use a short of six to create the digest. So you pass the content. The content is a concatenated string of your header and payload, the hash that you have. And then you digest it for base 64. Again, you have to base 64 escape it so that you can pass it around the web. And you get this hash thing, right? Now this is not encoding, right? This is encryption using the crypto thing to create an HMAC encryption, which means this is only one way. If you have the signature, you can't really decode it to understand what's inside it, unless you have the shared secret, right? This is where all the magic happens. So you can always have the answer to have the contents of this message been manipulated, right? Did somebody change one of these data? Admin was false, did somebody change it to true? And we look at how. But first, the token is just you just concatenate these three things, the header payload signature. This is what it looks like. It's separated by these dots in between. Cool. To do all of this, you can of course use a library and they're like millions of libraries. So as Shyam said, find a trustable one. So this one is called JSON web tokens. It has over a million downloads a week. So I hope it's secure. Like, I know it's secure. A bunch of my coworkers work on this. So it's secure. Use this. And to use this, you say JWT. Oh, shit. Dude, that's the timer. Don't touch there. I thought I'm out of time. Okay. So use JSON web tokens. You import it. And then you say, I'm going to use the payload. I'm going to sign it with JWT, pass the payload, pass the secret, pass the algorithm, right? And then it gives you this whole hash thing, right? Just like a nicer API. Just say sign payload secret, which is the algorithm to use. And you get this. There's a whole playground that is crafted bio zero. It's on JWT.io. It looks something like this. You can put in your token. If you put the secret as well, it's going to decode it for you. Or you can put the secret and encode it. It's a good way to test your implementation, while in dev. Cool. How do you use JWT? So whenever the user wants to access a protected resource on API, the browser should send this JWT, send this token using the authorization header, right? So it doesn't rely on cookies. It relies on headers, right? That's kind of important. So the first request goes to your authorization server. This again could be your own server or it could be a third party like odd zero. Send in the credentials. You get a token, right? This is the document that we'll use for the API. You send it to the API. Now you're not really sending the credentials. You're only sending this token. The API can verify if this token is valid and send you back the data. So how does this API server verify the token? That's the important part. So you have this whole big token, split it, split it by like the dots. You get the header and payload, which are just encoded. So you can URL decode it. Sorry, base 64 URL decoded. JSON parsed it. You get the data inside them, right? So you see this was the algorithm use. This was the payload, right? And now you can see the payload, but you have to verify, has this payload been tampered? Is this really coming from the original user? And to do that, you can just create the signature again, right? So we have the secret. We know the algorithm. The hacker doesn't or the client doesn't really know the secret. Only the authentication server and the API server know the secret. Nobody in between. So it's like the token is parsed and the API server at the end can verify by creating the signature again by using JWT again. And it gives you the signature. If the signature part of the token matches, you know it's legit. If not, then you mean something, something shady has happened in between. Again, you can use the same library. You say verify, you give the client token. You give the secret and you give the, you give the white list of algorithms that this API supports, right? So the API can actually support multiple authenticate, sorry, multiple algorithms for different clients. So you give a white list. It's optional in the spec, but you should always give it. I'll show you why soon. And then you get a function callback or a promise method. There's both. You can see if it errors out, then it's been tampered. If it doesn't error out, you just get the data and move on. Cool. Again, you can read the contents of the token, but you, if you don't know the secret, you can't change it, right? So you can't really tamper it. Here's a quick example. This is the payload admin is false. This is the token. If I change admin to true, the payload changes. But if I don't know the secret, I can't change the signature, which means on the server, when you do verify, signature will not match. You know something shady has happened, you reject it, right? Okay, let's talk about the authentication methods. The first one supported by the spec is none, right? It means no signature. So you just say JWT sign, you give the payload, you give null as the secret, and you say, don't use any algorithm. You sign it. Don't use that, please. Use something like HS256, which uses a shared secret, right? It's way more secure than none, of course. So you give the payload, you give the secret, you give the algorithm to verify. Again, you get the client token, you pass your shared secret, and you say, this is the algorithm white list, right? Then there is RS256, which is slightly more secure because it relies on a public and private key pair. The interesting part here is to sign it, you need a private key, which means the authentication server, the first one needs to have the private key. Sign it, create the token, pass it through the client, pass it to the API server. The API server doesn't need to have the same private key. It only needs to have the public key, right? Which means it's one less thing to protect. Only the, what do you say? Only the authentication server needs to protect the private key. You don't have it on multiple servers, so it's slightly more secure. The interesting part here is that by the virtue of its name, public key is public, right? So it means anyone can actually grab it from somewhere. You probably put it on GitHub and stuff. But the fun part is the hacker can verify if your token is valid, still can't change it, right? So that makes it pretty secure. The hacker can see the public key, but can't do anything with it unless you have the private key. So it's all cool. The last one is ES256, which is a slightly more interesting take on RS256. It also uses a public-private key, but these keys are typically smaller, right? So it's perfect because the signature created with them is also smaller. So the network payload that you have to send because you're sending this token on the header is also smaller. So it's slightly more performant over the network. So if you're dealing with low, what do you say, bad networks, this is really useful. The trade-off over there is it's slightly slower in comparison. Actually, not slightly, it's like at least five times slower, usually, in benchmarks. So if you have a lot of CPU, but your users use the internet, then you can use ES256 over RS256. Cool. Cookies, right? Cookies are the more popular authentication method. So I just want to do a quick comparison here. With cookies, you typically need a database, right? You have to store the cookie somewhere, right? JWT, we don't actually store it. We just pass it through tokens. We pass it through the header, right? Which makes JWT stateless. If you're storing the cookie in a database, that means for every request you get, you also have to query the database so that extra works. The server has to do, right? Extra requests, extra time performance, et cetera. JWT is stateless. You don't have to do that. Cookies are vulnerable to CSRF, right? So cross-site request for the CSRF is like when a hacker picks the browser into thinking that the information is actually coming from the same website when it's not and they usually steal your cookies. So what do you say? JWTs are not vulnerable to CSRF because they don't use cookies, but don't get excited. They are vulnerable to XSS, which affects both tokens and cookies. I'll talk about them soon. Sessions can be invalidated on demand with cookie because you store it, you can also delete it or you can flag it as invalid with JWT because you don't store them. You can't really do things like remote logout. So the, what do you say? The good practice is to always have an expiration, right? So given expiration and date time, don't create everlasting tokens, create really short-lived tokens that expire on their own. So even if they basically keep expiring, you keep generating new ones. It's useful to say that JWTs can actually be used at cookies, right? They're just hashes. So you can actually store them as cookies. You lose all these benefits, but if remote, instant remote logout is super important to you or for some reason, you really rely on cookies, you can use the same hashes as cookies as well. That totally works. Cool, so important security question. Can JWTs be hacked, right? Like everything else, yes. So the JWT spec is bulletproof. It's really good spec, but a weak implementation can get you hacked, right? So JWTs really get a bad rep sometimes. Like you see these articles where they criticize JWT for being a shitty algorithm, a shitty authentication method, because implementing it is super easy, but implementing it in the right way is requires a lot more careful effort, right? So it's super easy to get started, but then you have to kind of follow some rules to make it bulletproof. It's a lot like CSS, right? If you start it, it looks easy. It's just a simple syntax, but on day three you have completely screwed yourself. Cool, so the first attack I wanna talk about is cross-site scripting, because I said you are vulnerable to this. So, XSS is a attack where you basically insert, how do I put this? Okay, let me give you an example. So this is like the orange website where I'm putting a comment here, and in the comment I'm basically saying, I'm saying, yeah, nice post, but what I'm really trying to do is I'm inserting a script tag here, and I'm loading an image. In the image, I'm actually pinging my own attacker website, and I'm passing the local storage token, right? So I'm basically stealing. And if the server doesn't sanitize these comments, right? Sanitize user inputs, they'll just store it, and when the next user comes in, or when you open this, the user only sees nice post, but actually that code runs, and then I basically store their token, right? And there's like a super common, super old attack. The orange website takes care of it, so you don't have to worry so much, but because JWT are also stored on the client, they are vulnerable to XSS. Cool, more JWT specific things is, if you use a weak signature for, if you use a weak algorithm for your signature, right? So these are the three recommended ones in order of more security. So HS256 is shared secret, HS256 is slightly more secure because it uses public and private key. The authentication server has the private key, that's it. The APR server doesn't need it, it uses the public key. Third is if you use a weak secret, right? If you're using HMAC with this shared secret and use a weak secret. The funny part about HMAC is that these signatures are optimized for speed, right? So the verification is really fast, but the irony here is if somebody's trying to brute force your password, they can actually use the speed. It's gonna take them less time to brute force it, right? So it actually makes attacks slightly easier. So the spec actually says, like this is the recommended thing. If you're using a HS256, what do you say, algorithm, the key should at least be 256-bit instead, right? So you kind of need like very high entropy. Super secret 007 is a bad password. Lead password is, I don't know what I wrote there, but yeah, using like numbers and hash and like, things that would work for your Gmail password are just not as secure when it comes to HMAC. So you kind of have to use a 256-bit, which is roughly 32 ASCII characters. Okay. The last, this one is kind of, I introduced at the last moment, which is if you're storing the token in local storage or as cookies, I call it the Kulita Jori attack, which is there for someone to take, right? So number one, if you can just don't store these on the client side, don't store them, local store it, just keep them in the memory. And when the user refreshes, create a new token, right? It can be really annoying to implement, right? So you, the typical thing that people do is they still store it, but they give it a very short life. So that by the time somebody can use it, it's already gone. The other thing is keep expiring them and implement like a background authentication. Cause otherwise it would be really annoying. If every time I refresh the page, the page tells me, sorry, your session has expired, click login, go the whole reroute and come back, right? It's gonna be super annoying. So implement like a silent background authentication or zero JS kind of does that for you. So you just use open source libraries. Use good open source libraries. That's important. The next attack is the next mistake is reusing the same key across services. This, this is a really nice attack. I'm gonna mention this. So it's called a substitution attack. Look, something like this. You have your two servers, you have a client. In the first service, John Lowe is an admin. In the second one, he's not an admin. So you do the typical authentication thing. You send your credentials, you get a JWT, right? We're gonna call this JWT one and you use the JWT to access the data from this server, right? The typical method. Now, ideally what you should do is when you're talking to service to, you should send your credentials to the service to, it will give you a different JWT and you use this JWT to talk to the server, right? Now, if you're an attacker here, what you will definitely try is what happens if I use JWT one for service two, right? Just to try to see if the implementation is right or not. So I'm gonna send JWT one and if you're using the same secret for both the service, it's gonna check out, right? It's gonna verify and it's gonna work, but the problem is JWT one was for admin true, right? Not for admin false. So what the user can do is say, I'm just gonna pass admin true and your API servers kind of relies on the authentication servers to make this call, to pass this data of admin true or false. So if using the same secret, it checks out and you basically ask good. So you have two options there. The first one is always mention the audience key, right? In the payload, I mentioned this at the start, you can mention who is this token intended for. So always pass the audience and say this token is only valid for service one, right? And then if service two gets it, checks the audience, even if the signature is valid, but the audience is somebody else, it's going to reject it. Option two is just use different secrets. So even for the same payload, it's going to generate slightly different signatures so that it doesn't match. The recommended approach is just to both, right? Use different secret and always use audience as a good practice. Cool. Attack number six. If you don't verify the algorithm, you're going to get screwed. So this is called a signature stripping attack. It's really cool. Where this is the intended signature. This is the intended token. Strip the signature, right? And I told you JWT supports non-signature things, right? This is algorithm done. And then change the header to algorithm none, right? So I've done two things there. I've stripped the signature, I've changed the algorithm to none because headers are encoded. So I can decode them, change them and switched admin to true. Now on the server, when you do a verify, right? And if you're doing a client token and secret, just verify these. It's going to verify them based on the algorithm and header, right? Which is none. So it's going to say, okay, this token is obviously not encrypted. It's always true. Let's pass this along. So the bug here is you should always pass white list of algorithms, right? So sometimes this is again something I've seen. This is like a lazy approach where you say, I need to give a white list, but I'm just going to read it from the header, right? Because that's the intended header, right? Again, if the algorithm, if the hacker intercepts it and changes to algorithm none, you kind of just shot yourself in the foot. So always have a hard coded list of white list algorithms and only these are valid. So signature stripping attack doesn't work anymore because algorithm done is will get rejected. Our two of this attack is, this is super interesting, which is you can use the RS 256 key as the HS 256 secret, right? This is similar to the algorithm none attack where the goal is to fool the verification, right? And check this out. So this token was created with RS 256, right? Which means you had the private key on the authentication server to create the token, right? Public key is used for verification. Now, public key as the name reply implies it's public. So the attacker can get his or her hands on it, but it's okay because all they can do is verify, they can't really change anything using the public unless. So this is what the verification looks like on the server, right? You say, this is the token, this is the public key, right, verify. Can anyone tell me what's the bug in this right now? No, this is the verification. So on the authentication server, the one that generates the token, you need the private key, but on the verification side on your API server, you just need the public key, right? There's a very simple bug here first, which is, cool, yeah, somebody said algo's missing. Yeah, so I was testing you. Yeah, so I just told this, you always mention the algorithm whitelist. So we're gonna say these are the two algorithms that this API supports, right? There's still a problem here, which is notice how the signature kind of looks a lot like what HS 256 verification does. So it's like in HS 256, you'll do JWT verified token shared secret and the list of algorithms here. What you're doing is you're saying token, the public key and the algorithms, right? Which means there's something weird in this map, right? So what an attacker can do is change the, change the algorithm from RS 256 to HS 256. Of course do a privilege escalation by changing admin to true and then create a new token on the fly, right? So you create a new token, say I'm doing HS 256 with shared secret and give the public RSA key as the secret, right? So suddenly this is like a valid signature because it uses a secret, it uses HS 256 and on the server side, when you're doing the verification, you're just doing the same thing. You're saying use the token, use the public RSA key and these are the whitelisted algorithms, right? You see what the problem is here? The attacker can basically change the algorithm and because the function signature looks the same, can fool your verification into thinking this is not an RSA 256 signature, this is actually an HS 256 signature and because it's in the whitelist, it's gonna say, okay, cool, I thought you're gonna give me RSA but I also support HS, so cool. I'm gonna take it and it's gonna verify to true, right? The fix there is if you can, just use one algorithm authentication method across all your applications, right? Pick HS 256 or RS 256 and stick to them throughout so that you don't end up doing the, somebody cannot do like a substitution on you. If you can't, there are cases when you have like a generic server which has to support all of these, split them into two, right? Create two different functions to create to check for different methods, create a decode RSA token, create a decode HMAC token, RSA for RS 256, HMAC for HS 256 and based on what's in the header, send them to different functions, right? And then only put the whitelist in individual in one of them, right? So the RSA token only has RS 256 and then when you send it, it's gonna fail because it's actually going to check the RSA thing for the RSA one, even if you're trying to fool it with HMAC, the signature is not gonna match. So split them if you have to use both. Other things are like, you can also use the algorithm. Okay, that's good enough, okay. Cool, so that's, I'm on 30 minutes exact. So that's all I have. These are the resources. You can go to JWT IO for the dashboard to play around with it. There's a JWT handbook. It's like a 120 page handbook which has everything you can learn about JWTs. That's where I learned almost everything for this talk. It's on this URL. These are long URLs. I've just put them on my domain. It's at sit.studio slash JWT. You can get all the resources. And yeah, if you like this, give me a follow on Twitter. Thank you. Do we take questions now or in the session? I have time? Okay. So how does this compare to SAML tokens? To? SAML. I have no idea, sorry. Okay. I have another question actually. Sure. The tokens are actually created by the IDP, right? By the? The authorization server. Yeah. So the key which the client sends out to the authorization server, what actually is it made of? You're talking about the credentials part that, let me go to the diagram, just to make sure I understand you're right. You're talking about this key, right? So this is like your credentials, right? This is your username password, right? Like, oh sure. Yeah. So this is like a big way of saying that you need the credentials to get the authentication. The implementation details are very different. Usually what you do is, if it's like a third party, then you redirect them to the third party using like a unique token so that it verifies the third party hits your own servers to verify is this really your application that's trying to do it, right? There's like a handshake in between, between the authorization server and your own services. And if the handshake is successful, then it passes a token that can be passed. Okay. So is it, is it basically something like, if it's a multi tenant system, so are you, are you sending the tenant ID there in the key or the tenant ID? Oh yeah, totally. So this is where the idea of, if you have multiple services, then don't use the same signature. Sorry, don't use the same secret or same keys, right? Which also means that, which also means that if you have multiple, what do you say, servers that multiple services of your own and you're using a third party to authenticate, make sure you always pass the audience claim, right? So that for every audience or every API server that you have, it gives you a different token. Yeah, hello. So if you're using a single sign-on system like Google sign-in, Microsoft or let's say Auth0, so we would typically have a farm of thousands of servers and each would have its own public and private key pair. So the intent and service, how does it know to use which server's public key in this case? You're saying the authorization server, how will that know which one to use? No, no, no, the resource server basically. Oh, sorry, the API server, got it. You're saying how will the API server know which key to use? Which public key to use for verification of the... Oh sure, so the fun part is that this public-private key is between the authorization server and the resource server, right? So when you create a new public-private pair, you basically put one private key in your authorization server and you keep the pair of that, the public pair of that in your API server. So if you have three API servers, you actually create three different pairs and send, put the public keys in each one of them and then in the authorization server say, for this one use this private, for the second one use this private, for the third one use this private. Typically in implementation, how this works is if you're using a third party, then you say I'm gonna create three services on their dashboards, CLI, whatever they have and they give you the option of downloading three different public keys, which you put in the specific API server that you want them used, right? So the API servers, if they're three API servers, which means they're three different resources, each one of them has only one public key, not all of them, okay? Ooh, okay, I understand what you're saying. So when I say authentication, or sorry, authorization server, I don't mean authorization server instance, right? If there are five instance, doesn't mean you need five different keys, right? Because if you're load balancing, then they're basically duplicates of each other with the same keys. By authorization server, I mean, if this is like one, let's just call it authorization app, right? Authorization service. If it's a service, it has one, if you load balance, create replicas, all of them should have the same keys, yeah. Yeah, right, maybe I should just call it service instead of server, good point.