8

I have a static site which has forms. The forms submit to a Rails endpoint which captures the submitted data. The static site and the Rails endpoint are on the same domain, on different subdomains and all traffic is completely on HTTPS.

I understand how Rails CSRF works for server generated forms. But in my case, these forms are on static HTML pages. I understand all request headers can be faked, so can't rely on that.

If a strong solution is not possible for this scenario then my last option would be to move to server generated forms (which I want to avoid for now).

Any suggestions on a good approach to this would be most welcome. Or any pointers to a system or a library which already does this.

I could implement a REFERER check on the HTTPS POST request (in my case) - is that enough ? Can that not be spoofed ?

The CSRF prevention cheat cheat sheet says: Although it is trivial to spoof the referer header on your own browser, it is impossible to do so in a CSRF attack. - I don't quite understand this.

Any help would be much appreciated.

3 Answers 3

2

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.

1
  • 2
    Also note that the redirection attack only works with GET.
    – rook
    Oct 29, 2012 at 20:49
5

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.

6
  • 1
    -1 if you are so sure that an attack exists you should write an exploit for it. There is already too much misinformation in security, we need real PoC's to prove that a system is insecure.
    – rook
    Oct 29, 2012 at 19:23
  • 1
    I don't need to write an exploit; others already have. There's a long history of such attacks. The known attacks might not work on a fully patched modern browser today, depending upon how the Referer header is used, but I would not have any confidence that there are no other attacks, and I would not have confidence that people using older browsers are adequately protected. If you want detailed evidence for these claims, ask a separate question about the history of attacks on the Referer header, and I'll be happy to oblige. That is beyond the scope of this question.
    – D.W.
    Oct 29, 2012 at 19:39
  • 2
    There have been more SOP bypass exploits that could be used to read a CSRF token than there have been CRLF injection attacks to bypass the referer. There have been more remote code execution exploits written then all of these combined and if you are vulnerable to a CRFL injection on the client side you would also be vulnerable to remote code exectuion. If you can't write a PoC, then you have no business saying its insecure.
    – rook
    Oct 29, 2012 at 20:51
  • 1
    @Rook, A small correction: I didn't say it is insecure. I'm saying it is "very fragile", which is a bit different. (Let me re-express in different words, in case my answer was not clear: I would have more confidence in a defense based upon CSRF tokens than a defense based upon the Referer header.)
    – D.W.
    Oct 29, 2012 at 22:14
  • 1
    If the site has no log-in system or accounts, and the CSRF protection isn't necessary for account security and is just a less-critical tool to stop people from using CSRF to get other people's browsers to spam comments for them, then relying on the Referrer despite its shaky history doesn't seem so bad.
    – Macil
    Feb 11, 2016 at 18:58
-1

It's effectively your rails endpoint that needs to protect itself. It needs to differentiate between your static pages and someone else's malicious page on the internet.

I agree that having the rails endpoint check the referrer is a fragile way to authorize access.

One possibility is to have the rails endpoint have a route that is not CSRF protected, and does nothing, but lets the CSRF cookie be set. A "null form". All static sites on your domain can hit it before making other AJAX calls.

Presumably, if you are using AJAX, you are on the same domain, which means you can see the cookie. If that endpoint were hit from another site, they would not get the cookie because they are on a different domain.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .