3

I'm planning to use synchronizer tokens for CSRF prevention, but OWASP recommends checking the referrer and origin headers too. I've been trying to figure out the correct logic for this, but my experiments suggest that there is no valid way to check due to the way Firefox behaves.

Firefox doesn't send the origin header for same origin requests, which I would have thought means you have to allow requests through that lack an origin header. I've just experimented with data URIs though and it looks like Firefox doesn't send the origin header from them either, which would mean an attacker can just direct the user to a Data URI that auto submits a malicious form.

This

data:text/html;base64,PGZvcm0gYWN0aW9uPSJodHRwOi8vd3d3LmV4YW1wbGUuY29tIiBtZXRob2Q9IkdFVCI+CjxpbnB1dCB0eXBlPSJzdWJtaXQiPgo8L2Zvcm0+

is a link to a data URI containing a form that submits to example.com.

Which is the following code base64 encoded:

<form action="http://www.example.com" method="GET">
<input type="submit">
</form>

When I open it in Firefox with the web console open it shows no origin or referrer header being sent.

What am I missing here? Is there some logic I should use on the server that will allow through requests from FIrefox but not malicious requests from data URIs?

5

The Origin header on it's own is not always enough (it's only sent on POST and CORS requests, but what you have is a GET request), but the Referer and Origin headers usually is (I'll include an example where they aren't sufficient at the end).

By default, Firefox does send the Referer header for same-origin requests. This is in-part why OWASP recommends using both the Origin and Referer headers:

To determine the source origin, we recommend using one of these two standard headers that almost all requests include one or both of:

  • Origin Header
  • Referer Header

If both headers are not present, which should be rare (your base64 case being one of them), you can then either choose to allow or deny it.

If neither of these headers is present, which should be VERY rare, you can either accept or block the request. We recommend blocking, particularly if you aren't using a random CSRF token as your second check. You might want to log when this happens for a while and if you basically never see it, start blocking such requests.

As OWASP says though, there are cases where these headers may not be present, so it recommends using an additional check, of which it recommends using CSRF tokens, especially if you do not block when neither header is present and correct.

checking headers is a reasonable first step in your CSRF defense, but since they aren't always present, its generally not considered a sufficient defense on its own.


When requiring headers isn't enough:

If the site allows for user-generated content, like posting an image, it can be possible to do request forgery from the same origin. A GET request could be as simple as adding the following img tag to a public posting.

<img src="/forum.php?whatever=parameters">

Additionally for a POST request, if a user could also inject an HTML form (say the site is smart enough to filter JavaScript, but not HTML forms), it could be possible to trick people into submitting it, also from the same origin. This would at-least require user interaction though.

  • I don't understand. Why is the Origin header on its own not enough? – Arin Jan 25 at 0:42
  • @Arin It's only sent on POST requests and CORS requests. That may be enough in some cases, but not all. – Alexander O'Mara Jan 25 at 0:46
  • Thanks for the quick reply, I appreciate that! Would it be safe if you simply rejected requests that the Origin header is not sent with? – Arin Jan 25 at 0:47
  • @Arin I believe so. That's what OWASP recommends doing. – Alexander O'Mara Jan 25 at 0:51

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.