Web Security, v2

Using CSRF Tokens

Steve Kinney

Steve Kinney

Temporal
Web Security, v2

Check out a free preview of the full Web Security, v2 course

The "Using CSRF Tokens" Lesson is part of the full, Web Security, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Steve demonstrates how to implement protection against CSRF attacks using tokens. He shows how to generate a unique token for each session, hide it in a form, and validate it on the server-side to prevent unauthorized requests.

Preview
Close

Transcript from the "Using CSRF Tokens" Lesson

[00:00:00]
>> Steve Kinney: And so we'll implement this in a moment, but let's look at it, and then we'll talk about it. Look at it, and then we'll do it, which is put an unpredictable value that you're checking for. And there are some nuances to this, right? For instance, if you put it with the cookie, what did you even do, [LAUGH] right?

[00:00:18]
Cuz it's getting sent along. If you use the same one all the time, cool, they'll also hard code that into their form. There are ways that you can screw this up, but the idea is put some unpredictable value in there that only you know, right? And then you should be in a better place but any cheat that you do will come back to bite you and so far like actually we just got like ten of them that we just rotate.

[00:00:47]
Good, now one tenth of your people is susceptible to the attack, right? And all the attacker needs to do is go visit ten times and get them all or whatever. So there are ways that you can make this not great for yourself, but yeah, and you can put in the header when we put that token in there like you saw before, but you're like, I only have a single-page app, or I can't set request headers.

[00:01:10]
You can put it also any HTTP header, you can put in the actual markup too, and that will count. That works for CSP as well, as you can Play before. Cool, and so how do we solve this issue? That's a great question. I'm glad you all asked it.

[00:01:28]
Cool, so we've got that C-Surf bank, and what we wanna do is basically put some kind of token in that form that is unique. So that even if someone put a form on their page, if they do not have our secret little token, then our server will be like, get out of here, you're not real.

[00:01:53]
And so doing that is somewhat easy. I will say though that depending on what you look at, there's a lot of stuff out there that talks about npm.im/csurf which was originally, and again, this is express specific, but there's a lot of content out there. It's like, yeah, yeah, you could just get that csurf module and you put it in there.

[00:02:20]
Except it's not secure. Luckily, I think these days, NPM will yell at you and it's marked as deprecated and you can't do it. But let me just save you the hassle for when you go look this up later and find out that you get a big red screen when you go try to install it.

[00:02:38]
There's actually, I think I have a link in the, there's one called Tiny CSurf, which it does the same thing. It's 20 lines of code, but spoiler alert, it shoves it in the cookie, right? So whatever, cool. But we can implement something similar as well. And yes, one could argue there's probably a lot of edge cases and stuff along those lines.

[00:03:05]
But I think for the most part, we can get a pretty simple version in place. So let's go into our app. And when they log in, this is kind of very similar to the code we ended up with in that story we were just playing around with, where we have sessions now, right?

[00:03:27]
Or I guess a cookie jar, whatever. We have sessions, that's for the post, though. Let's see. All right, here we go. And we make that rando session id. And no one asked the question, but I did prepare for it,if someone did ask, so I'm going to answer it anyway.

[00:03:44]
I wanna say can I just use a UUID for a session token? You can because what the UUID uses under the hood node's crypto module with a little bit of extra bit shifting. So you can use UUID, you can use whatever. I could use both if I wanted to.

[00:04:04]
Let's actually just use both because why not? Just to show you the two ways to do the same thing. So there is a pretty popular node library called UUID. It's got a whole bunch of different algorithms. V4 has a very low chance of collision cuz again, if you're gonna even source up in the database with unique keys, it kind of stinks if you actually crash into one.

[00:04:26]
Can you theoretically generate two UUIDs that are the same? You theoretically can. And you can also, I don't know, I could also throw a three pointer from the other end of the court, possibly. Right, it's not gonna happen. And so we can do that as well. And yeah, you can use either one.

[00:04:48]
You can use both, you can use them for different reasons. I don't really care what you do. This is mostly as a mechanism which is generating a different value, right? Yeah.
>> Student: So I think, memory serves the version is important also, right? So V4 is relatively randomized, it's very low risk in terms of collision.

[00:05:12]
Is version five is deterministic, right?
>> Steve Kinney: I think so.
>> Student: Which is one reason you would wanna stay away from it in this scenario.
>> Steve Kinney: Yeah, I believe that's true. I'm not gonna riff on crypto enough, [LAUGH] and go, yes, totally, that is. That jives my understanding as well.

[00:05:33]
And so we can go ahead, there's a bunch of places you can store the token. We know that the wrong answer is doing it once and storing it. It just hard code it into your app. We know that's the wrong answer. There's levels of nuance in between, right?

[00:05:49]
So, for instance, could you do it on every single request? You could, right? But that's if you got to store it for the response. Yeah, well, I guess you could do it every single response, and you've got to store it for the next request. So, that could be a lot of rows in your database for forms that no one's gonna submit, right?

[00:06:09]
With load on the database and also in terms of storage, right? So yeah, is that super secure, but it also creates a bad UX if they hit the back button, right? And now the one on that back page is not the current one or the two tabs open, or something along those lines.

[00:06:23]
It can get weird. You can come up with all sorts of weird race conditions. Hardcoding is wrong. And so somewhere in the middle is for the length of their session. And if you're like, yo, we let them log in for two years, okay, then maybe less. But in this case, our cookies are scoped to session.

[00:06:40]
We'll say for this session that you're logged in, here's a token for you. That way if it is the closest browser they go to something else and then they hit the attacking page, that session, this is why we're not tying it to the user ID, that session no longer exists even though the user does.

[00:06:56]
So we'll say const token and I pulled in uuid, right? So we'll create a token and I happen to know that this database table already has a column for tokens. And so we're not storing it with the user, we're storing it with the session in this case. And I am no longer susceptible to the obvious injection attacks.

[00:07:20]
I don't speak in absolute anymore. Like only assist does that. So we can throw in the tokens of the database as well. And you do need to then inter a third value in there and the token. Cool. Now because I'm developing, I do need to like my current actually no, this, yeah, this session won't.

[00:07:40]
Token because when I made the session ID the concept of a token didn't exis,t so like my code will break, break, yeah it'll break. It just won't work it is it broken or is it working as expected but not what I want, all right, unclear. That's a philosophical issue we can deal with later so let's log out.

[00:07:59]
Cool, now we can go ahead and say finnthehuman, and we'll say adventure. I say we say that like I'm guessing what the password is. One thing that I have on these apps, if you ever need it while you're like, because again, I think that there are things you can probably explain these or string together, there is this that gives you at least what's in the database.

[00:08:23]
So we can see that we've got the session because I am deleting the sessions from the database when they log out, right? So now, we have a token in there, that's uuid, we have a sessionId and this is _ _meta on all the example apps that exists, right?

[00:08:38]
So if you're ever like, what is in my database? You can go here and see as well. Ultimately, if you forget what the username and password is too, it'll also work. It's just running through the database tables. Cool, cool, cool. And so now I've got this token. Now, having a secret token and not doing anything with it does not get you very far.

[00:08:59]
So now what we need to do is Express has this idea of middleware, it's gonna be different depending on what your server side technology is, but honestly, it's the same basic idea. And so I can go into this current user and we grab the session ID from the cookie.

[00:09:19]
And then we go ahead and we try to pull that user. I guess what we would need to do is get the session as well. And, I mean, we don't necessarily have to do it in the middle where actually now I think about it. And let's go ahead.

[00:09:38]
We only really needed for that transfer. Over that, yeah, the transfer page, right? Is that what it's called? Yeah, login, transfer, that's post get. So this page right here, if I go back, I know slash account, let's do slash account. [SOUND] The account. So here we need to go get that token as well, cuz we need to, like, pass it into the form, right?

[00:10:10]
So we can go ahead and we can say something like,
>> Steve Kinney: Let me think about this for a second. So I've got the session getting the user, yeah, I'm not doing anything else here. So let's do a,
>> Steve Kinney: Token equals get and we can say, select ocean, yeah, this will work.

[00:10:38]
Select the token from sessions where the user ID is, this, I think like the way that SQLite works is that it's on the object and we need to use await. I'm just gonna console log that real quick cause just make sure I didn't live code SQL wrong. Cuz I've never done that before.

[00:11:00]
I've never accidentally,
>> Steve Kinney: All right, yep, there's my token, cool. So now we have it, and all we need to do is render it on the page, so I can go ahead and pass in that the token, you could call it CSRF token, if that, the naming is depending on the other stuff going on your app, whatever makes you happiest, you can do so.

[00:11:24]
Now we've got this, we're gonna render it. We're passing the token to the page, so we can also go into this account. And then, if you are using forms, this will work. If you're using Ajax and you need to maybe grab it, grab that token with JavaScript and include it in the request somehow.

[00:11:41]
But we're using a regular form, so we can totally do this. So we'll go into the form. And then this is where you can just kind of pop in. If you look at a lot of regular forms, here it's called CSRF. I think I only called it token before, right?

[00:12:00]
It's effectively a hidden field, right? And so because this has the name underscore CSRF even though it's not visibly apparent in the form, it will be submitted with the rest of the form data right along with the name for mount and the name for the recipient. You will also now get this token in there as well.

[00:12:20]
Okay, we generate a token. We hit it in the form. Until we validate that token, it doesn't really help us too much either, so we need to get that as well.
>> Steve Kinney: I regret putting on my page now, but whatever. I'll tell you what the alternative was in a second, but like this is the perils of live coding.

[00:12:45]
Sometimes you make choices and you have to live with them in front of people. So we've got the token there and then we could say that on the POST request,
>> Steve Kinney: I think of the POST is the transfer, right?
>> Steve Kinney: Transfer, right? We can go ahead and we can also, again, get that same token, right?

[00:13:06]
Cuz it's attached to the session at this point. So as long as they still got the same code, we get the same token, and we can say, I hate myself. All right, one change that we're gonna make, again, the perils of live coding is we're gonna say that.

[00:13:20]
We named it CSRF. I'm smart, I did a good thing. So we'll say if the token that they have stored in the database does not equal the csrf token that we got here.
>> Steve Kinney: Then in that case, what we're gonna say is, yeah. So we're gonna just say unauthorized.

[00:13:44]
I don't need to tell them why. You send me a voc, risk request a token, I don't need to leak information out to people honestly. Now, if it is important in your client side code to explain what happened for error reporting, but again, every piece of information you give away is some clue on how to thwart your best efforts.

[00:14:06]
When they log in, we create a token. We hide that token on the form. If they don't have the right token, cuz this is some rando page that someone sent me a mess with me, and a token I only see in my version of the page, then we get to the point where I should have a relatively safer experience.

[00:14:25]
Cool. And so let's see. So now if I go in here, I should, I don't think I have to re-log in. Let's send $12. Cool, that worked. And then if I go to that slash evil again, unauthorized, right?. It so the attack didn't work because they didn't have the token, it rejected it outright.

[00:14:45]
And this is technically on the same site. Because I'm trying, I'm not worried about the cookies, but I'm trying to show the token, the cookies would have been sent, but I'm still protected, even if somehow the cookies are sent to the request, right? All of my like, I've messed up cookie attributes by accident somehow, right?

[00:15:02]
All the security issues that I've dealt with in the last year or two is someone made a boo-boo, not somebody was reckless. And so if they made a boo-boo with a cookie, I'm still protected by another layer. If someone made a boo-boo with a token, then the cookie protects me.

[00:15:17]
The idea is you can make a boo-boo in one area and not compromise your user's security.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now