Skip to content

Latest commit

 

History

History
274 lines (143 loc) · 8.63 KB

csrf-tutorial.md

File metadata and controls

274 lines (143 loc) · 8.63 KB

Csrf tutorial

2019-09-09

Let's get practical.

The goal of this tutorial is for the application developer to really understand the CSRF attack from a practical point of view. We will trigger two types of csrf attacks and see how we can protect our application against them.

In this tutorial, I will use the CSRFProtector class to protect a CSRF attack against a form via POST, then we will see a use case to protect ajax services (we will call simple php pages via GET).

We will also see the differences that the page security makes.

All examples assume that you have a running webserver to test them.

You can download all files, they are in the tutorial-files directory in this repository.

To follow the tutorial, copy the (tutorial-files/)csrf directory under your web root.

Summary

Setup

Open two windows (or tabs, but separate windows is better for this exercise) in your browser: we will use one for the user, and one for the attacker. In both windows, open csrf/summary.php.

Unprotected form

Do the aforementioned setup.

Click the "Form unprotected" link for the user, and the "Form unprotected attack" link for the attacker.

Now in the user window, this is just a simple form with not protection at all. I use it just as a reference to get started.

You'll see a submit button, click on it to submit the form, and you should see the success message in green, which indicates that the form action has been executed.

We can post the form again and again, we will always get the success message.

Now go to the attacker window, and click the submit button. You should see a successful result appearing in the iframe, indicating that we've successfully tricked the user and access the protected resource (in this case unprotected).

It was not hard for the attacker, he just needed to know the url of the form.

Note: we imagine that the attacker has actually send that link to the user, and that the user clicked on it, and so if we see the green message in the attacker window, it means (for the purpose of this planet) that the attacker successfully found a breach in our application.

In other words, a green message in the attacker window is BAD. So, with this unprotected form, this is very BAD.

Protected form

Do the aforementioned setup.

Click the "Form protected" link for the user, and the "Form protected attack" link for the attacker.

Let's talk about the user window. This time we have a token, generated by our CSRF tool.

We also have a form, and when we submit the form, the token is sent along with it. In fact, the token that you see is an input of the form.

Post the form. You should see the green message, with the valid token value being used by the csrf tool.

We can post the form again and again, this will validate every time.

The thing to be aware of is that the token value is regenerated on every page refresh.

Now let's try to attack that page. In the attacker window, there is a form to post the token value.

Note that the urls and the token key are already setup, so that we just need to find the right value to break in.

First, let's give it a try with an empty value, and post the form. We should see a red error message indicating that the given csrf token is not valid.

That's because we didn't find correct the csrf token value.

Now refresh the user window and copy the token value (in the input) in your clipboard.

Go back to the attacker window, and paste it into the input, and submit the form.

Now you should see the green message, because we've provided the right token.

Note: try to post a second time, this should not work, because when we first posted the attacker form (successfully), a new token was regenerated.

Another thing that you can test is:

  • go to the user window and copy the token value
  • post the user form
  • go to the attacker window and paste the token value that you have, and post
  • this shouldn't work, as the token has been regenerated when the user posted the form

In other words, form security with CSRF tool is quite good, because the CSRF token value is regenerated every time (at least in this scheme where the action attribute of the form leads to the same url as the one actually displaying the form).

Unprotected services

Do the aforementioned setup.

Click the "Services unprotected" link for the user, and the "Services unprotected attack" link for the attacker.

Again we will see the basic design of the page when ajax services are involved.

Go to the user window, and click the links (access to service one and two), you should see the green message in the iframe below, indicating that those services have been successfully executed.

There is no protection on the services, they are just publicly available to anyone. We can click on the link as many times as we want, with the same results.

So now go to the attacker window, and post the forms for service one and two. You should see the green messages in the iframe below the links.

Again, nothing special here, it's unprotected, so we just need to know the url.

Protected services

Now for the real use case with ajax services.

Do the aforementioned setup.

Click the "Services protected" link for the user, and the "Services protected attack" link for the attacker.

In the user window, notice that one token has been generated by link.

Note: technically, you can use one shared token for all dynamic services, but I recommend against it as it increases the chances that an attacker can brute-force your application (since if he could then brute-force any service, since they all have the same token).

So when you click the link, basically the token is attached to the GET request, and the backend service checks for that token.

Click either of the links, you should see the success message, indicating that the token value transmitted over GET is the same as the one stored by the CSRF tool (in the php session).

Now the problem with this approach is that we cannot refresh the page (we imagine that this is an interactive gui, and the user won't refresh the page, so he might click three times on the same link and the same token will be re-used).

That's the main problem with ajax links.

So every time you click the link, you should see the success message.

Now go to the attacker window, you just need to know the token value (copy it from the user window) to be able to gain access to the services.

This might be hard for the attacker (to guess the token value), or not, I don't know.

The pages security

This is a follow-up of the previous section (protected services).

Imagine that the user uses the protected services page, and then goes to another page.

Well, since we didn't delete the token yet, the attacker could continue trying to brute-force the protected services page, and ultimately, gain access to the service (provided that the user doesn't log out).

Let's try that.

Go to the user window, in the protected services page, refresh, and copy the token value for the service one in your clipboard.

Now click on the "Go to another page without page security" link and stay there.

Now switch to the attacker window, and paste the token value in the access service one input, and submit. You should see the green message. Ouch.

This means while the user is wandering elsewhere, her account is not safe (or at least not very safe).

But we can do better.

Redo the same steps again from the user window, except that you click the "Go to another page with page security" link this time (instead of the link without pages security).

What happens is that at the end of the script, we call a token cleaner function which will delete all tokens that aren't used on the page. And so when the user accesses this page, all the previous tokens are removed.

This means that now as the attacker, even if you have the correct token value, the token has been removed, and if you try to paste that in the attacker form you would get the red message.

Now it's more secure.

Note: in terms of implementation, what you need to do in order to have that level of security, is to call the deletePageUnusedTokens method at the end of every page.

You can leverage some php handlers for that, such as register_shutdown_function, things like that.

So that's it. Hopefully this tutorial helped you understand the mechanisms of the CSRF attack, and gave you some ideas about how to prevent it.