Simple CSRF protection using nginx alone

20,319

Solution 1

The point of CSRF tokens is to require attackers to read a value from your domain in order to send requests.

Therefore, you can have a separate endpoint in the API that simply returns a CSRF form token.

Attackers will not be able to read the token due to the same-origin policy (for the same reason that they can't read a token from HTML source), so you will be safe.
This has the disadvantage of requiring an extra HTTP request.

Also, make sure that the response is not valid Javascript, or attackers can run it as a <script> tag and use prototype & property tricks to read the value

Solution 2

Since you can't have server side sessions, you need a solution that doesn't require the token to be stored on the server. Instead, what you need to do is have your nginx implementation generate some sort of token that you will include in your response to the browser. This value should appear in a place that isn't included automatically in the request when an attacker sends a request on behalf of another user (i.e. hidden input field or meta tag on the pages your application generates), and it should also be stored in a cookie (that obviously would be sent automatically in a CSRF attack). When the request is received by your application, it can verify that these two values are equivalent. If so, you can forward the request to the API. If not, you know the request did not come from your site and you can reject.

There are at least two ways you can do this:

Good: csrf_cookie: abc123 (cookie) csrf_param: abc123 (parameter or header)

Better: session_+_csrf_cookie: sessionid_val_--abc123 csrf_param: abc123 (parameter or header)

The reason that the second solution is superior to the first is that the first solution is vulnerable to cookie forcing. The second is safe from this because if a MITM messes with your session cookie, it will invalidate the session anyway. With the second solution, you can simply strip off the token before proxying to the API.

Of course, all of this assumes you are using HTTPS.

Solution 3

Install a WAF (web application firewall) to inspect HTTP/HTTPS traffic, deny malicious requests, and generally act as an additional layer of security in your web stack. A properly configured WAF can protect your site from SQLi, XSS, CSRF, and DDoS attacks, as well as provide brute force attack mitigation and zero-day threat patching.
There are a few open-source WAF options available for nginx. See https://help.dreamhost.com/hc/en-us/articles/222784068-The-most-important-steps-to-take-to-make-an-nginx-server-more-secure

There is also a simple nginx module which compares either the referer or the origin header to the host header. If the domain name doesn't match, HTTP response 403 is returned. See https://github.com/gartnera/nginx_csrf_prevent

Share:
20,319
Anirudhan J
Author by

Anirudhan J

Graduate student in Machine Learning from Courant Institute of Mathematical Sciences, New York University. Also have hands-on experience as a Full stack developer in various technology stacks such as .Net, J2EE, ROR. SOreadytohelp

Updated on July 09, 2022

Comments

  • Anirudhan J
    Anirudhan J almost 2 years

    I have an nginx server serving plain HTML and JS files.

    The js code then calls various REST API to GET/POST data from API servers.

    If nginx receives a request for /api/ location, it forwards the request to another server which handles all the APIs. This api server is built in Ruby on Rails.

    Since all my plain HTML pages are delivered by nginx directly, I cant have server side sessions while they are rendered.

    What can I do to prevent CSRF attacks?

  • woky
    woky over 8 years
    Could you please elaborate on why is the second one better? Since you explicitly mention cookie forcing, I assume that you're concerned with plain-text requests. But then in both ways you showed, if some request is sent over plain-text, the MiTM attacker will inevitably learn both the session cookie and the CSFR token and can continue on its own. So what's your point?
  • rbhitchcock
    rbhitchcock over 8 years
    Cookie forcing is a MiTM attack that occurs over an encrypted connection. Without being able to read the contents of the message, an attacker can still change the value of cookies due to browser behavior. I suggest reading the following write-ups if you would like more information: scarybeastsecurity.blogspot.com.co/2008/11/cookie-forcing.ht‌​ml michael-coates.blogspot.com.co/2010/01/… homakov.blogspot.com.co/2013/06/…
  • woky
    woky over 8 years
    I misunderstood the cookie forcing but I still think this is bullshit. In the last link that touches the subject the author can't even explain why the session cookie can't be separate. I think the key point here is that the authentication/session cookie must be secure. If I'm wrong, perhaps you should explain it in your post instead of referring to other articles that don't even explain it.
  • rbhitchcock
    rbhitchcock over 8 years
    I'll try to break it down for you again. It seems like at this point you understand that cookie forcing allows a MITM to modify (overwrite) a secure, HttpOnly cookie sent over HTTPS. Even though the attacker cannot read it, they can still overwrite. So, if one relies on a csrf cookie + HTTP param for csrf protection, an attacker can control both values. If you append the csrf token to a session cookie, when the attacker overwrites the session cookie, the whole session is invalidated, thus making CSRF impossible.
  • woky
    woky over 8 years
    That's not true. If the authentication/session cookie is secure (HTTPS only), the attacker can control only CSFR cookie because MiTM cannot work.