3
votes

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
CodeReview would be better suited for you, I believe.Script47
Browsers will block cross-site requests so any request which has a valid CSRF token in a cookie is normally from a client browsing your own domain (unless you enable CORS in some routes, in that case you need to beware).apokryfos
stackoverflow.com/a/20518324/487813 is a good read for thisapokryfos
@apokryfos no , browser do not block cross-site request in general. They block requests where you expect to get data back. A XMLHttpRequest uses CORS. But a hidden <form> that is submitted using JavaScript, can still send a POST request to a foreign domain. And such request will include all cookies of the user. Storing a CSRF in a Cookie is as if you don't have a CSRF token.t.niese
@apokryfos the relevant part that covers this is [...]Simple cross-origin requests generated outside this specification (such as cross-origin form submissions using GET or POST or cross-origin GET requests resulting from script elements) typically include user credentials, so resources conforming to this specification must always be prepared to expect simple cross-origin requests with credentials.[...] (4 Security Considerations)t.niese

2 Answers

4
votes

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.

2
votes

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.