Turning off authenticity token in Rails 2 for web services? - ruby-on-rails

Instead of just filling out the form in HTML it should also be possible to just send a post request containing the params.. Is it possible to turn off the authenticity token if, for example, the Accept flag is set to 'application/JSON' in the HTTP header?

The request forgery protection works on the basis of checking the content-type of requests and it only checks the requests that can be made by a browser. No browser is able to generate a request with the content-type set to "application/json" for example. That's why the rails forgery protection routine won't check it. So, if you want to make a json request to your application, set the content-type header to "application/json" and it should work.

I know there is a way to turn it off for a controller or an action. Not sure about the content type. Wouldn't it be easier to just add the authenticity token to every json request? There are quite few articles around the web how to do it (for example here and here).

Wouldn't it be easier to just add the authenticity token to every json request?
Yes, but then the client would have to send a request first just to get the token and then another with the actual POST request, which does not make sense IMHO..

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.

Invalid authenticity token when POSTing to a Rails API

I have a web application that gets & stores some data through a Rails API.
When I try to "post" to the Rails API, I get an error ActionController::InvalidAuthenticityToken. I know one option is to simply disable the authenticity token requirement on my Rails controller.
Is it possible to have my web app providing a correct authenticity token when it calls the Rails API? How can I do this?
2 Part answer for you here.
First if you are going to be using Rails as an API I would recommend you use another way of validating that the user making the request is actually the user they say they are such as creating a unique token upon account creation or login that can be returned in the initial response and provided as a HTTP header in subsequent requests. If you are worried about the security of this you could optionally base64 encode the key plus some other value and decode it server side before comparison.
If you still wish to use the CSRF method baked in to Rails you can do so as long as the user is making a request from the webapp using AJAX or whatever. If you have the csrf_meta_tags ERB in the header of your layout file you can get the value and set it in the X-CSRF-Token HTTP header. Using jQuery it may look something like:
$.ajaxPrefilter(function(options, originalOptions, xhr) {
var token = $('meta[name="csrf-token"]').attr('content');
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
});
This would cause it to be added to every ajax request made using jQuery.

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