I’ve watched the Pluralsight course on web security, which states that to mitigate CSRF attacks, the website should return two “paired” CSRF tokens to the client, one in a hidden form field and another in a cookie, that are associated to the user’s session. These tokens are issued whenever the user visits a page with, e.g., a form.

Now, since the attacker’s website can’t get the hidden form field token (same-origin policy), it cannot issue a valid request to the page containing the form.

But why are two CSRF tokens necessary in order to prevent CSRF? Isn’t the form field token sufficient by itself?

  • Yes, the cookie is not strictly necessary, as long as you have access to the original value somewhere. Putting it in an HTTP Only cookie provides an easy (stateless) way to track that, but if you have the value stored in the session or something like that, you don't need the cookie. – Joe Mar 15 '18 at 17:46
  • What do you imagine that the form field token is being compared against for correctness? – Eric Lippert Mar 15 '18 at 17:54
  • @EricLippert - The reason for two tokens is that they are compared for correctness? The server doesn’t store tokens? Otherwise one token would be enough... The reason it doesn’t store tokens is to move token storage completely to the client? How are the tokens linked to a particular user? And is there any reason for not using two form fields instead of a form field and a cookie? – Shuzheng Mar 15 '18 at 18:02

The pattern you are describing is known as "double submit cookie", and it is a common way to defend against CSRF. The point here is that it doesn't require the server to remember the token. The client sends the token in both a cookie and some other way, e.g. in a form field. The server checks that both tokens are identical.

This works because the attacker can not read or write the cookie, and hence can't reproduce it in the form field. That is why it has to be sent twice:

  • If there was only a cookie, it would be sent automatically on every request and provide no protection at all.
  • If there was only a form field, there would be nothing to compare it to and the attacker could just enter any value.

There are other defences against CSRF, that only use one token. The most common is to just store the correct value in a session variable on the server, and check that a form field matches it. No cookie is needed. However, this has the drawback that the server has to maintain a per user state.

  • 2
    In the course, the tokens in the form field and cookie are not identical, but paired using strong cryptography. – Shuzheng Mar 15 '18 at 19:38
  • @Shuzheng I don't know what benefit the crypto gives, but it sounds like the basic idea is the same - check that the two tokens "match". – Anders Mar 15 '18 at 23:26
  • Why is “double submit cookie” good? I mean, the server must link the issued tokens to the particular user, so some session state is needed? If not, then tokens could be used several times to post a form. Or the attacker could himself get a valid pair of tokens and use these to forge requests on behalf of the user. – Shuzheng Mar 16 '18 at 8:53
  • @Shuzheng No, there is no server state. The tokens just have to match each other. They do not have to match anything on the server. The tokens are not per request, so they can be reused. But an attacker can not forge a request since she can not read or write the value of the cookie. – Anders Mar 16 '18 at 9:06
  • Would the server issue new tokens on each request then? Your point is that the cookie is HTTP-only, so it cannot be read/write by JS? – Shuzheng Mar 16 '18 at 10:42

One token is enough provided it is the hidden form field, and is per request (meaning you receive a token in every response to be sent in next request). Please note that the token should not be stored in a cookie since cookies are sent automatically.

There are different ways to do things (and some are framework specific). The two token process also serves as a good way to solve the CSRF problem. The token in the cookie and on the page are cryptographically linked. So the server has to do this check and proceed with processing this request if everything is good.

  • If the client and server communicate over HTTPS, is it then necessary to issue a new token in every response? I mean, the attacker has no way of knowing the hidden form token received in the initial request? I’m just curious. – Shuzheng Mar 16 '18 at 7:26
  • Yes it is necessary.The attacker can have multiple ways example a cross site scripting vulnerability can lead to compromise of the token. Applications have vulnerabilities that can compromise these tokens. Being on HTTPS does not solve every problem. – H4X Mar 16 '18 at 17:13

To prevent CSRF attacks, the CSRF token must be matched against the expected token.

The website needs to store that expected token, and a common way to do that is by setting a cookie.

If both tokens match, then the form is valid.

  • Yes, but why are one token not enough? – Shuzheng Mar 15 '18 at 17:48
  • Because you can't match your token against anything if there's only one token. – Benoit Esnard Mar 15 '18 at 17:49
  • Ahh - so the server doesn’t store the tokens itself? - It moves the storage completely to the client instead? If the server stored the tokens, then one token would be enough. But if the server doesn’t store the tokens, how does it link tokens to a particular user? – Shuzheng Mar 15 '18 at 17:58
  • If the server stored the token (in a database / session for example), then one token would be enough indeed. – Benoit Esnard Mar 16 '18 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.