CSRF Protection on static pages

Personally, I do not recommend using the Referer header to stop CSRF attacks. It has two issues:

  • First, it is fragile. There is a long past history of attacks on the Referer header, involving (variously) exploits on plugins (e.g., Flash), bugs in browser APIs (e.g., XHR), and redirection. To be clear, I'm not saying that checking the Referer will necessarily be insecure; I'm just arguing that I think it's more fragile, and I would have more confidence in a solution that uses CSRF tokens.

  • Second, some browsers and corporate firewalls block the Referer header for privacy reasons, meaning that you'll be forced to block legitimate users. So the Referer header is simply not a good solution.

Instead of using the Referer header, I would recommend that you use CSRF tokens.


I can make any request to your server, with any headers and values that I want. So an attacker can very easily send you a packet with a referrer that's picked by him. But how'd you go about this in a CSRF attack?

CSRF works by me sending you to a webpage that I control, and then that webpage redirects your browser to the webpage to execute the CSRF. For example I could send you (via that attack page) to https://example.com/usermgmt.php?action=delete&user=1, which might make you inadvertently delete userid 1.

What your browser does is set the REFERER header (when loading usermgmt.php) to whereever it came from, for example http://malicious.tld. If usermgmt.php checked the referer, it would notice that it didn't come from the same domain. Thus you can't (by default) spoof referers for CSRF.

One catch here are things like login pages. Consider this: https://example.com/login.php?returnTo=index.php. A CSRF attack only works when the victim is logged in already, else the attacker could just load the URL himself. And if you are logged in, the login page probably just redirects you to the return URL directly. Now what if you write usermgmt.php?action=delete&userid=1 as the return URL? It will redirect from login.php to usermgmt.php, and the referer received by usermgmt.php will be https://example.com/login.php?returnto=x. It seems totally legit, but it's not.

Also, some browsers may not include a referrer for privacy reasons, which would then break the website. I don't know of any browsers having this option ("feature"?) without installing a special add-on, but you never know.

So the best solution is to use CSRF tokens, and I certainly would if you are going to host something for a bigger audience, but if it's for a closed usergroup you're probably okay checking the referrer.