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?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With