CSRF Protection with HTTP GET requests in Rails - ruby-on-rails

I understand that Rails by default doesn't have CSRF protection for HTTP GET requests, because, it claims they are idempotent. However, there is sensitive information that is returned to the user from these GET requests, and, I would't want a malicious site retrieving this information.
What is the best way to protect HTTP GET requests from CSRF in Rails?

To be able to read the response to a CSRF attack’s request, an attacker would need to get the victim to execute his JavaScript code. And in that case, the access would be restricted by some Same Origin Policy.
Assuming the attacking request is really cross origin, the Same Origin Policy for DOM forbids access via DOM (e. g. when embedded using iframe) and the Cross-Origin Resource Sharing (CORS) regulates cross-origin requests via XMLHttpRequest as follows:
If the request is a simple cross-origin request, i. e. simple method with only simple header fields, then that request will be sent (this is similar to HTML-based CSRF). But accessing a simple cross-origin request’s response depends on whether the response allows resource sharing.
Other cross-origin requests require a so called preflight before the actual request is sent. That request is sent to check whether the server allows requests from the origin the preflight is sent from. And only if the preflight succeeds and the response to the actual request allows resource sharing, the response can be accessed.
So to conclude: Unless your server supports CORS and explicitly allows sharing with any other origin (i. e. Access-Control-Allow-Origin: *), a CSRF response – if the request was allowed at all – won’t be readable by the attacking site.

Related

Why does JWT need to be sent as a Bearer Token header?

I am adding JWT Auth for a completely new frontend to a legacy Rails backend.
Upon HTTP request, it seems most sources suggest I send the token back to the server via Bearer Header.
Why? What is the additional value of sending via header (bearer or basic). What can't I simply pass the JWT back to the server via .json and authenticate the token from there.
What benefit does an Authorization header give me, and moreso, what does a Bearer Authorization header give me?
I can of course simply follow everyone's example, but want to understand why. The bearer docs are verbose and hard to understand what I'm gaining over simple sending the JWT as part of the data in the request.
Thank you.
You can technically send a json body on each request with the JTW but that would be non standard behaviour (for instance, GET requests should not have a body via the spec).
A more standard way would be to provide an Authorization HTTP header.
The Authorization header is not specific to JWTs and its role is to specify an auth scheme between the client and the server.
Another way would be to include the JWT inside a cookie but that would make the behaviour browser specific while the HTTP header can be sent by virtually any HTTP client.
P.S
Bear in mind that contrary to Auth cookies which are sent by the browser automatically the Authorization header needs to be set by the client explicitly.

Deny access to a rails route if request does not originate from app

I have a route in my application that returns results from an LDAP query. I'm using a privileged account for this as it needs to return information that a regular account can't access.
Is there a way to deny users access to this route if they're not using it via one of the application's views? What I'm trying to prevent is a someone reverse engineering it and building their own app to gain access to the PII.
There is no reliable way to say this request originated from this view vs. this request originated from (e.g.) the command line.
An HTTP URL request doesn't have a verifiable source of origination. There is a "referrer" HTTP header which is intended for saying where the previous request originated, but it is not for security and completely spoofable, and not even always included in the request.
Somehow you'll need to authenticate the request. Don't invent your own way. Use devise or some other tested tool to build an authentication strategy, and figure out how to modify your application to work with existing conventions of HTTP request authentication (secure token, cookie based auth, etc.)

Why does rails not verify XHR requests for CSRF?

In:
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Which determines cross site request forgery validation. The following function:
def non_xhr_javascript_response?
content_type =~ %r(\Atext/javascript) && !request.xhr?
end
Ends up meaning no XHR requests are validated for CSRF even if the token is invalid?
Why is this? Do XHR requests mean that CRSF doesn't need to be validated with Auth Token?
That isn't correct. Rails checks the CSRF token for all non get/head posts, whether they are ajax or not.
In addition, since rails 4.1 Rails also checks for a csrf token for non xhr GET requests with javascript format. This is to prevent information being leaked when accessed in a cross domain request via JSON-P requests. For xhr the browser will have already enforced cross domain restrictions. This is where the method you have found is used: to see if a request needs this extra check.
If you go back far enough in time, rails did use to exempt ajax requests from CSRF checks, because of the aforementioned browser imposed restrictions. However Rails only knows that a request is an ajax request because of the presence of an X-Requested-With header and it was found that this could be forged, so this was removed

Security for cross-origin resource sharing

I have 2 ruby on rails app sitting on 2 different domains (say www.exampleA.com and www.exampleB.com. I want to share resources between the 2 apps and I'm using CORS:
exampleA.com sends http POST request to exampleB.com.
At exampleB.com I'm checking request.env['HTTP_ORIGIN'] to make sure that the request comes from exampleA.com. If true I respond by setting the response headers to allow the http post request.
My question is can I use request.env['HTTP_ORIGIN'] as the only check to verify the identity of requester?
Is it possible for someone from www.exampleC.com to fake their HTTP_ORIGIN to look like www.exampleA.com and post malicious data? If so what's the best way to verify requester identity?
Origin is one of several header fields that cannot be set for a XHR request by page authors. So you’re safe to trust the Origin information of XHR requests.
But it is still possible for an attacker to send forged requests with malicious data directly. So you’re still required to validate incoming requests.
Sorry, but it is trivially easy to fake most client-provided data, origin included, and hence it should not be used for any type of security.

CSRF token problem on requests from outside the browser to a Rails server

I need to make an HTTP POST request from outside the browser, but the Rails back-end is not accepting the authentication (error 401). I know I need to pass a CSRF token in such cases, but it's not working.
When I make the request through a form on a browser, it works as expected, but when I try to simulate an identical request (in terms of headers and cookies) from outside the browser (using curl, for example), the authentication doesn't work.
Two small changes allowed me success without a browser: (1) turning off protect_from_forgery, which validates the CSRF or (2) using GET instead of POST for the request. In both cases, passing the cookie is enough. That means the problem is definitely related to CSRF stuff.
So, my question is: how can I make a CSRF-protected HTTP POST to a Rails server without using a browser?
To clarify, the process is broken in three steps:
Login: returns a cookie to identify the session;
New: a GET request that returns the CSRF token to be used later (uses the cookie);
Create: a POST request that submits the information I want to create (uses both the session cookie and the CSRF token).
The only step which fails is the third one.
Assuming your CSRF token is cookie-based, then the program you use to make your requests needs to track cookies. Check out the --cookie-jar option in curl.

Resources