25

Is it ok to put the CSRF token in a cookie? (and in every form, as a hidden input, so I can check if they match, of course) I heard someone say that doing so, beats the whole purpose of the token, though I don't understand why. It seems secure to me.

And if it is secure, is it any less secure than puting the token in the URL's ?

Is there any other method?

Where can I read more on the subject?

UPDATE: So far no one can tell me how is the cookie method insecure, if it still has to match the token from the form, which the attacker shouldn't be able to get, unless he uses another hack like XSS, which is a different matter, and still doesn't make a difference between using cookie and url token.

UPDATE 2: Okay, seems like some famous frameworks use this method, so it should be fine. Thanks

HappyDeveloper
  • 12,480
  • 22
  • 82
  • 117
  • The double-submit cookies approach works, but beware the [security implications](http://security.stackexchange.com/a/61039/5002) of such an approach. – Gili Jun 14 '14 at 20:41
  • Because of those implications implementing the double submit cookie (or the cookie to header token technique that Angular claims to be using) seems tricky, even for the more popular frameworks as mentioned [here](https://owasp.org/www-chapter-london/assets/slides/David_Johansson-Double_Defeat_of_Double-Submit_Cookie.pdf) ([video](https://www.youtube.com/watch?v=2uvrGQEy8i4)) – DZet May 19 '20 at 15:06

5 Answers5

21

Using cookies works, and is a common practice (e. g. Django uses it). The attacker cannot read or change the value of the cookie due to the same-origin policy, and thus cannot guess the right GET/POST parameter.

Tgr
  • 27,442
  • 12
  • 81
  • 118
  • 12
    **IMPORTANT:** the server must always check that the CSRF value submitted by form and the value received via cookie does match. The CSRF protection does not work unless the server cross-checks data from cookie with POST (or GET) data. – Mikko Rantalainen Jun 04 '13 at 11:13
  • 1
    @MikkoRantalainen it's not important. it's **crucial**- otherwise devils can send "delete my account links" - where the cookie will be sent and authorized. so a match HAS TO BE MADE. – Royi Namir Jun 01 '14 at 06:38
  • What I don't understand: Can't an attacker with a malicious website use JavaScript to read the cookie? Does the browser as a default disallow reading cookies for other websites? – Zelphir Kaltstahl Mar 22 '17 at 12:02
  • @Zelphir yep, as I said, [same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy). – Tgr Mar 22 '17 at 17:32
  • What **I** don't understand: is comparing the hidden field token with the cookie token an alternative to comparing the hidden field token with a token stored server-side at the time of token generation? Is there a preference between the two approaces? – temporary_user_name Nov 22 '18 at 14:38
  • 1
    @Aerovistae Yes, the idea is that you put a value into the form when you generate it, read it back when you receive it, and the two values matching is proof that whoever submitted the form could also read it (=has same-origin access). Cookies and sessions are the two straightforward ways to persist that value so the server knows how to verify. The session is marginally more secure in that you can use different values for different regions of the site, and you don't have to worry about subdomain / parent domain attacks; they are also marginally harder to implement. – Tgr Nov 23 '18 at 10:41
  • Would it be possible to remove the use of cookies in a single page application such as React by saving the CSRF token into the web application's state (ie: [react state hook](https://reactjs.org/docs/hooks-state.html)) and submitting that value as part of X-CSRF-TOKEN header along with the same value in the POST/PUT/PATCH request? – Alex Aug 08 '22 at 19:58
  • @Alex how does your server know what the token is? Cookies can be read by the server, client state cannot. You need either cookies, or a server-side session (in the end also sort of cookies, since that's based on a session cookie), or tokens with some kind of cryptographic proof of authenticity as mentioned in another answer. – Tgr Aug 09 '22 at 07:15
2

Check out the Encrypted Token Pattern, which allows stateless CSRF protection without the need to store tokens on the server.

Paul Mooney
  • 1,576
  • 12
  • 28
1

If you decide to put the CSRF-token in a cookie then remember to mark that cookie as HttpOnly. If your site has a cross-site scripting vulnerability the hacker won't be able to read the CSRF-token. You can check the cookies that can be read by JavaScript using the command console.log(document.cookie) in any modern browser console. If you have session cookies or other sensitive cookies these should also be marked as HttpOnly.

Further reading:

https://www.owasp.org/index.php/HttpOnly

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • 3
    How would you read the token then to send it along with the header (=Double Submit) on the client side? Putting the CSRF Token in a protected cookie is only possible when the server also provides a form with a hidden input-field with the token. Many APIs don't provide forms, so you must be able to read the CSRF-token with Javascript. So I guess one better makes sure to not have a XSS vulnerability. – Christian Benke Jan 31 '16 at 21:40
  • 1
    @ChristianBenke Why could you not render the form on the server side including the token, which the server has to know anyway? Or do you mean high level frameworks, where one does not work with templates anymore, which do not provide the functionality to include the token value in the form? – Zelphir Kaltstahl Mar 22 '17 at 12:04
  • @Zelphir I wrote "client side". So if you have for example a REST-API, there are no templates and no forms provided by the server. – Christian Benke Mar 23 '17 at 20:13
  • HttpOnly is an absolute must for cookies that store session IDs to prevent against XSS attacks, but CSRF is another issue. To prevent CSRF, the client must know the CSRF token, whether it's in a hidden field in a form, or attached as a header of an ajax call via JavaScript. – tybro0103 Mar 27 '17 at 18:17
0

"CSRF works because many sites use GET requests to execute commands.", so, many sites don't use the GET method as expected, because these request must be idempotent: see the rfc2616.

"The CSRF parameter is already there in the cookie and it gets sent along with the session.", so how?

The cookie is only used has a token storage, as the DOM when we set the token in a hidden input field. A piece of javascript must get the token value from this cookie, and set it as a parameter in the URL, the request body or in the request header. It will be check on the server with the value stored in the session. That's the Django way to handle the CSRF token.

Javascript can't access the cookie from another domain, due to the cross domain browser protection, so I don't know how a malicious user can force someone to send the correct token along a forged request. With an XSS, yes, but XSS defeat the common CSRF countermeasures.

I prefer giving this clarification, because I think it's an important question and not so easy to handle.


GET request must be used to get a resource and/or display its data, it must not be used to change its state (deletion, property incrementation or any changes).

The CSRF validation must be done server-side, it seems to be obvious, but I put it as a reminder. This method can't be a vector of attack if you observe this recommandations.

Dinacel
  • 86
  • 2
  • 5
  • 2
    Note that `idempotent != safe`. For example `GET http://example.com/api/item/123/delete` might be implemented idempotent (that is, the result is identical no matter if the GET is submitted 1,2,3,..., or N times). – Mikko Rantalainen Jun 04 '13 at 11:06
  • "might be implemented idempotent", but it shouldn't : the state has changed after a call to this delete endpoint and should respond with a HTTP 202 Accepted (if the resource has not been deleted/changed), not a 200 OK (it has been deleted successfuly). There's best practices, and so, a GET should never be used for nothing else that output the current representation of a resource. – Dinacel Jun 05 '13 at 17:24
  • 1
    I agree that `GET` *should* only be used for requests without visible side effects but somebody reading the HTTP spec might be following the "idempotent" part, which allows for more effects. – Mikko Rantalainen Jun 06 '13 at 05:27
  • 1
    @David: that's not what idempotent means. Check out [HTTP method definition specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html). According to the spec, PUT and DELETE are idempotent but they aren't safe method. – Lie Ryan Oct 14 '13 at 02:05
-2

Using a cookie defeats the purpose of CSRF. Here's why:

CSRF works because many sites use GET requests to execute commands. So say Bob has some kind of administrative web account and he's logged into it. Some request could be made like:

http://somesite.com/admin/whatever.php?request=delete_record&id=4

So now Bob gets linked to an attack site (someone is trying to mess with his data). The attacker then loads the above URL in an image, probably with another ID and deletes some other record. The browser loads it because Bob is already logged into his admin site so he has a valid session.

CSRF seeks to eliminate this by adding a secure parameter to the transaction. That parameter should rotate on every request and then be resent by the browser. Making the URL look something like this:

http://somesite.com/admin/whatever.php?request=delete_record&id=4&csrf=<some long checksum>

The idea is that now the attacker has to guess "some long checksum" to create an attack. And if that checksum rotates on every request well it should be virtually impossible.

BUT if you store that checksum in a cookie you're back at square 1. The attacker no longer has to guess it. He just crafts the original URL. The CSRF parameter is already there in the cookie and it gets sent along with the session. It doesn't stop the insecure behavior from happening.

Cfreak
  • 19,191
  • 6
  • 49
  • 60
  • But how is the attacker gonna get the token to put it in the hidden field of the form? If he doesn't there wont be a match, and I will reject the request. – HappyDeveloper Dec 16 '10 at 17:28
  • Also, you said that CSRF works because ppl use GET to execute commands. But CSRF works with POST too AFAIK. – HappyDeveloper Dec 16 '10 at 17:32
  • @HappyDeveloper he can get the token with XSS+XHR like the Sammy worm, other wise its off limits due to the same origin policy. – rook Dec 16 '10 at 18:21
  • 3
    I don't see how this is a perfect answer, if it says that the attacker only needs the original URL: Again, how is the attacker gonna make the form token and the cookie token match?. If my site is vulnerable to XSS that's a complete different thing, and I still don't see how it would be any less secure than using the token in the URL's. If the attacker can get the token from the form via XSS, then he can get it from the URL too. Am I wrong? – HappyDeveloper Dec 16 '10 at 19:24
  • 1
    @HappyDeveloper - Yes CSRF can happen with POST too. GET is more common because it's easier. The form token has to match whatever shows up in the cookie. So the attacker doesn't have to do anything. He just sends the request back and the cookie gets read by your server. – Cfreak Dec 16 '10 at 20:35
  • 1
    @HappyDeveloper you have no idea whats going on. Please read the most basic introduction to CSRF, and the OWASP CSRF prevention cheat sheet. – rook Dec 16 '10 at 20:36
  • 1
    @Cfreak Also POST based CSRF exploits are equally as common and just as easy to exploit as GET. You just call `document.getElementById(1).submit()` to automatically submit the form when its viewed. – rook Dec 16 '10 at 20:44
  • 7
    It is clear from (at least the current version of the question) that HappyDeveloper intends to ALSO pass the token via an HTTP parameter (via hidden form field) and then cross-check it against the cookie. This is a completely acceptable way to prevent CSRF attacks. Also, don't worry about hackers using XSS to steal the token from the cookie. If an attacker can place XSS on your site, you have much bigger concerns that CSRF and must deal with the XSS problem first. – Eadwacer Dec 19 '10 at 08:28
  • Old thread, I know but it pegged my curiosity. Just my 2 cents but if you have a function f(c,t) with c as cookie value and t as form token to verify the 2 on the server side, there's no need for f(c, t) to evaluate c === t is there? It could be an intrisic formula to generate c from t or vice versa so getting the token is now not enough, the attacker needs to guess the relationship between the two as well. – fred May 30 '12 at 16:58
  • 1
    I don't understand why the downvotes. +1 . a devil can send a link which delete the account , the cookie will also be sent. the think which won't be sent is the form value. so a match between coockie and form should be made . that's all – Royi Namir Jun 01 '14 at 06:37
  • Either you are trolling or you have misunderstand it. The cookie does not replace the request parameter, cookie is used along request parameter, it is used on server to verify the request parameter. – Ali Shakiba Jun 05 '15 at 17:40