Simple CSRF protection using nginx alone
Asked Answered
Q

3

12

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?

Qualitative answered 29/12, 2013 at 14:33 Comment(0)
A
6

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

Antediluvian answered 29/12, 2013 at 14:38 Comment(0)
I
3

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.

Infrangible answered 20/2, 2014 at 22:25 Comment(5)
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?Mansion
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.html michael-coates.blogspot.com.co/2010/01/… homakov.blogspot.com.co/2013/06/…Infrangible
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.Mansion
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.Infrangible
That's not true. If the authentication/session cookie is secure (HTTPS only), the attacker can control only CSFR cookie because MiTM cannot work.Mansion
C
1

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

Cosper answered 13/5, 2018 at 0:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.