Check out a free preview of the full Web Security, v2 course
The "Finding a CSRF Exercise" 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 a CSRF attack can occur by manipulating the app's code and sending unauthorized requests. He also discusses the risks of including personal information in query parameters and suggests alternative methods for CSRF protection, such as double-signing cookies or implementing multi-step actions.
Transcript from the "Finding a CSRF Exercise" Lesson
[00:00:00]
>> Steve Kinney: We got this app called Socialite. It's a social media app. It's got an idea of a form, but let's go, I'll sign up and let's see. I'm gonna say that my username is, let's go with finnthehuman again. finnthehuman, password would be password.
>> Steve Kinney: And we'll sign up.
[00:00:24]
Maybe I'll hit the button right. We can see that there was a post in here from somebody else, seems handsome. We'll go ahead and we'll say hello, and then we're gonna pull up another app, just for fun. Because sometimes if you work really hard, you just wanna stare into the void for a little bit.
[00:00:46]
That's how I feel after live coding for too long.
>> Steve Kinney: Yeah, that WebSocket error, don't worry about that. That's Vite compiling my assets, saying, I didn't wanna deal with Tailwind and CSS. This is fine. Your server's running, and that's the important part. And especially for the void where if we look at it, it's on 4009, so let's go put that in another tab.
[00:01:17]
>> Steve Kinney: It's peaceful, it's serene, it's good, right? We could even go look at the code for the void. And if we look at the server, basically a static file server, right? It's got no routes to speak of. It's got this one HTML file, right, which got a tiny little bit of markup, I guess some Tailwind.
[00:01:39]
And that's it, a simpler time on the Internet, almost as it was meant to be. Wait a second.
>> Steve Kinney: I didn't post that. What happened? How did this happen?
>> Steve Kinney: Take a few minutes so you can figure out how I just got hacked. It might have something to do with the void.
[00:02:04]
That might have been a complete red herring [LAUGH] yeah. So I would check there, see if we can figure out where things went down cuz there was no JavaScript in that app.
>> Steve Kinney: Did anyone find it where my issue is?
>> Steve Kinney: Yep, like I said in the very beginning, one, GET requests that change state, bad cuz they can get called from anywhere.
[00:02:32]
And two, your CSRF attacks don't need to come from JavaScript, right? And three, yeah, this is that bug we're talking about that got Twitter in the kinda early days and some other ones, which is this one was hiding in a background URL where, yeah, that background doesn't load.
[00:02:51]
The black background still works, but it does send the GET request, right, which does have the kinda cookie attached to it as well, right? And so that's kind of like nature of CSRF attacks. So the void is everyone's favorite public service announcement of don't include your CSRF tokens in a GET request, but also don't even do it in a form, right?
[00:03:13]
Because remember we're talking about you can secure your cookies and have HTTPS, right? HTTPS is great, use it and it will encrypt all of the bodies of your requests. But GET requests don't have bodies, right? So it means if you have a form with method GET, they all become query params and you can't encrypt query params cuz that's not how URLs work, right?
[00:03:39]
The browser doesn't know where to send it, doesn't know how to get through DNS all the way to the server if the URL is encrypted. So the moment that you have a form with a GET, not only do you leave yourself open to what we've talked about previously, because then you have an endpoint with a GET.
[00:03:55]
But you are also then transmitting your CSRF token, which everything, obviously anything man-in-the-middle, any packet sniffer and man-in-the-middle of that. Also, there's a story short. So I will tell it to you, never include any kind of PII in a query param, right? Or you will join me in the pantheon of people along with my co-worker Alex, who had to spend way too much time on the phone with third party trackers, right?
[00:04:25]
Because email addresses and stuff like that are PII. And the European Union doesn't like when you let PII sleep in other people's databases and you need to be able to clear that stuff out. And not only on a security level with your CSRF token, but also with any kind of PII.
[00:04:45]
Even if you're trying to do a search where it's like, I just wanna have the filter in the query param you do for everything else. Not if it's any kind of personal information cuz that is gonna get transmitted in cleartext over the Internet, right? Phone numbers, email addresses, Social Security numbers, if they are in a query param in any way, shape, or form, they are public data, and you probably don't want that.
[00:05:06]
So GET requests, again, there's no world that you should have to do that. But even search, if it's email address, you gotta find something. You gotta put it in the body or in a header or something. Referer-based validation, yes, referer is spelled wrong there cuz it's spelled wrong in HTTP headers, and now we live with it.
[00:05:27]
Which is to say when you go from one site to another, it says, who sent you? One, that's not reliable cuz if someone puts a no referrer in the a tag, you're not gonna get it. And two, it is very easy to spoof. You can check for that also if you really want to, but also a lot of times, it will be missing and it's not particularly reliable.
[00:05:49]
There's another pattern which is let's say, I cannot put this in the form for any reason whatsoever, right? One is to then have your cookie, and then what's called double-signed, which is then you take the cookie plus the CSRF token and you sign it again, right? If you can get away with not doing this, you can look it up.
[00:06:08]
It's an alternative if it exists, if you need it. I would caution you that it is a lot more of a hassle. If you can render it in the page, great. Even if you have to somehow fire a request to get it in Ajax, and then attach it to the fetch request.
[00:06:24]
If you truly need it in the header, you can do some of the stuff we'll see later with password hashing and try it out like that, cool. There's another option too, right, which is CRSF attacks are effective when it's easy to perform the action. A single POST request will do it.
[00:06:42]
So another decent way particularly for serious and destructive actions is to just not make it easy [LAUGH] right? And I think an example that you've probably seen before in the past is deleting a repo on GitHub, right? So if one wanted to go delete a repo, you start out with this model says, I want to delete this repo.
[00:07:06]
Then you have to do another request. And finally, you do need to type in the name of the repo. Now that's technically somewhat of an unpredictable thing. So there's multiple steps in there as well, right, which makes it a lot harder to just hide a background URL somewhere or click a submit form, right?
[00:07:24]
It's just to make it a lot harder, make more of a back and forth. You can argue that there's a lot of overlap between what we did with the token and this, which is it's not whoever does a CSRF attack. This is also to save you from yourself, too.
[00:07:37]
So this isn't just a security thing. This is also before you delete your company's repo. But I think it's sort of the same thing of there's a lot of back and forth that needs to happen. And with CSRF attacks, you can't do that, right? You can send requests, but you don't get the responses cuz it was never in your browser or your code to begin with.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops