Is my CSRF protection method secure?

Viewed 1099

I've been doing my own CSRF protection using PHP. From what I've read I decided to use a cookie to implement my protection but feel a little confused as to whether my method is secure against CSRF attacks.

So my method follows:

  1. User sends request to login

  2. Server checks if a CSRF token is set, if not create one and store it in their Session and create a Cookie with the token as well

  3. Validate the CSRF token through checking if it is in the POST request, if not then check for the token in $_COOKIE

  4. Send message back if token is invalid...

I decided to use a cookie to store the token as this will work for Ajax requests and I won't have to include it every time I use an Ajax POST.

What I am confused about is couldn't an attacker just make a request; POST or GET and because the cookie is there it just gets sent with the request anyway, thus being a valid request as the token is sent with the browser every time?

2 Answers

The cookie should not contain the CSRF token. Only the client side session storage should contain it. And you should not against a CSRF that is in the cookie.

If you would check a CSRF that is send with the cookie you would bypass the idea behind CSRF.

A simple attack scenario would be a hidden form on a foreign website:

<form method="method" action="http://site-to-gain-access-to.tld/someactionurl">
  <!-- some form data -->
</form>

And this hidden form will be executed using javascript without the user's intervention. If the user is logged in on the site site-to-gain-access-to.tld and if there is no CSRF protection active then it would be like if the user itself would have triggered that action, because the session cookies of the user will be send with that request. So the server would assume that it was the user that triggered that request.

If you now would place the CSRF token in your cookie you would have the same problem as with a session.

The CSRF token has to be always sended only as part of the request body or url, and not as cookie.

So the the highlighted parts:

Server checks if a CSRF token is set, if not create one and store it in their Session and create a Cookie with the token as well

Validate the CSRF token through checking if it is in the POST request, if not then check for the token in $_COOKIE

would break the CSRF protection. It does not matter if the CSRF is stored in the cookies as plaintext or with a server side encryption.

As long as "User sends request to login" refers to the initial GET request for the login page, this is correct. The CSRF should be generated and stored on the GET request and validated during every POST.

What I am confused about is couldn't an attacker just make a request; POST or GET and because the cookie is there it just gets sent with the request anyway, thus being a valid request as the token is sent with the browser every time?

Yes. CSRF tokens are not secret. They simply confirm that a POST is made only after making an expected GET request. Meaning someone can only submit a form if they requested the form in the first place. It prevents an bad site from sending a user across to your site with a POST. It does not prevent an attacker from making a GET request, grabbing a token, and making a valid POST.

From OWASP:

With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker's choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests.

Related