Why are CSRF tokens necessary?

You are right, your solution (a cookie that only works on the same origin) would prevent anti-CSRF tokens from being necessary against CSRF attacks. As for why nobody implemented this, we can only guess. Perhaps it is because a solution is already present in current header values, namely by checking the Referer header. Using the referrer is also more flexible than a NoCSR flag: you can whitelist multiple domains or subdomains.

Note that your proposal would not magically solve everything: cookies are also used when someone clicks a link and opens a page where they are logged in. Let's say you search for 'stackoverflow' and you click the top result, then you would like to be logged in even though the request came from another origin (namely your search engine). Therefore, you would need two cookies: one that has the proposed flag and one without. Or, alternatively, the flag would not apply to GET requests so that normal links work, but then you leave a lot of website still vulnerable when they modify the server state in response to GET requests (many applications will perform actions when you do requests like GET /deleteUser/123).

It's almost as if the browser should just include a flag about whether a request was across origins and then the web server can decide whether this is a dangerous action that should not be done across origins... which sounds a lot like the Referer header!


Since this question was asked, just such a cookie flag has been added to modern browsers: SameSite. From the spec:

5.3.7. The SameSite Attribute

If the attribute-name case-insensitively matches the string
"SameSite", the user agent MUST process the cookie-av as follows:

  1. If cookie-av's attribute-value is not a case-insensitive match for "Strict" or "Lax", ignore the "cookie-av".

  2. Let "enforcement" be "Lax" if cookie-av's attribute-value is a case-insensitive match for "Lax", and "Strict" otherwise.

  3. Append an attribute to the cookie-attribute-list with an attribute-name of "SameSite" and an attribute-value of "enforcement".

5.3.7.1. "Strict" and "Lax" enforcement

Same-site cookies in "Strict" enforcement mode will not be sent along with top-level navigations which are triggered from a cross-site document context. As discussed in Section 8.8.2, this might or might not be compatible with existing session management systems. In the interests of providing a drop-in mechanism that mitigates the risk of CSRF attacks, developers may set the "SameSite" attribute in a "Lax" enforcement mode that carves out an exception which sends same-site cookies along with cross-site requests if and only if they are top- level navigations which use a "safe" (in the [RFC7231] sense) HTTP method.

Lax enforcement provides reasonable defense in depth against CSRF
attacks that rely on unsafe HTTP methods (like "POST"), but does not
offer a robust defense against CSRF as a general category of attack:

  1. Attackers can still pop up new windows or trigger top-level navigations in order to create a "same-site" request (as described in section 2.1), which is only a speedbump along the road to exploitation.

  2. Features like "<link rel='prerender'>" [prerendering] can be exploited to create "same-site" requests without the risk of user detection.

    When possible, developers should use a session management mechanism such as that described in Section 8.8.2 to mitigate the risk of CSRF
    more completely.

It's supported as of IE 11 (on Windows 10 only), Edge 16, Firefox 60, Chrome 51, Safari 12, and Opera 39, according to caniuse.com.


I'd say mostly complication. A link sent through another application would carry no site referrer, so that is a hole that needs to be considered. One could focus on only passing requests from within the site, but there could be an XSS vulnerability that would create CSRF-like behavior that would be stopped by using a nonce.

In very short summary: the nonce method already works and isn't very complicated to implement. This proposed method may end up being much more complicated to implement, would break backwards compatibility, and would require the already existing nonce method as a stop-gap.

Finally, there are other non-repetition behaviors for which you might still desire a nonce.