Setting CORS headers do not solve my CORS problem - ruby-on-rails

I'm trying to call an endpoint(POST https://target-endpoint.com/authentication) from another origin(https://origin.com) with below header settings, but CORS error has remain raised.
Is there any mistake in my settings?
authentications_controller.rb
def create
response.headers['access-control-allow-origin'] = 'https://origin.com'
// some impl
end
routes.rb
Rails.application.routes.draw do
post :authentication, to: "authentications#create", via: :options
end
error in chrome console
Access to fetch at 'https://target-endpoint.com/authentication' from origin 'https://origin.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
error in chrome network tab
If you have any idea, please let me know.
Thanks,
other conds.
heroku, with stack 18
ruby 2.6.4
rails 6.0.4.8

Before browsers make a cross-origin POST request, they first perform a so called CORS-preflight request to make sure that the target of the POST allows the request.
For that, browsers make an OPTIONS request to the URL and check the CORS headers of the response. Only if the respone headers of this preflight request indicate that the request is allowed, browsers will perform the actual POST request.
For you, that means that your create action (for the POST request) won't receive a request unless you also reply to an OPTIONS request first.
While you could implement this "by hand", it is usually a much better idea to use existing CORS implementation such as the rack-cors gem.

Related

Redirect from ruby on rails to angular giving Response for preflight is invalid error

I have an app with front-end in angular 4 and back-end in rails 5.
I have integrated a payment service in my app which posts success response back to the given url. Since the response is in post format so I cannot handle it on angular.So I have given back-end's url as the redirect url.
Now I want to redirect to front-end(angular) providing response of the payment service.
On using rails redirect_to method it is giving me an error:
Response for preflight is invalid
but sometimes the error is
Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
How to resolve this issue?
See the following documentation and follow how you can avoid pre-flight requests. If pre-flight request is a must then it need to be fixed in the server with the right methods, origins and headers.
When a preflight request will be sent is clearly documented under the following documentation.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
In particular, a request is preflighted if any of the following conditions is true:
If the request uses any of the following methods:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
Or if, apart from the headers set automatically by the user agent (for example, Connection, User-Agent, or any of the other header with a name defined in the Fetch spec as a “forbidden header name”), the request includes any headers other than those which the Fetch spec defines as being a “CORS-safelisted request-header”, which are the following:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
Last-Event-ID
DPR
Downlink
Save-Data
Viewport-Width
Width
Or if the Content-Type header has a value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Or if one or more event listeners are registered on an XMLHttpRequestUpload object used in the request.
Or if a ReadableStream object is used in the request.

How send redirect as post request. Spring Security

i have my own AuthenticationSuccessHandler and overriding method onAuthenticationSuccess, where i need to redirect to some page with parameters from request before authenticate (i hope you understand what i mean, sorry for my english)
getRedirectStrategy().sendRedirect(request, response, targetUrl);
How can i do this with POST method (by default it is GET method)
You may do it without sendRedirect method using HTTP1.1 307 Temporary Redirect status code.
But AFAIK this is not a common practice and not all web browsers may support this.
Maybe server-side forward will suit your case.
Update:
If you want to send POST-redirect using spring-security API you may implement your own RedirectStrategy.
DefaultRedirectStrategy uses response.sendRedirect that will result in 302 response code sending by servlet container (I'm not sure about every container, at least tomcat sends 302).
Update 2:
You may send 307 back setting response status and "Location" header yourself:
resp.setStatus(SC_TEMPORARY_REDIRECT);
resp.setHeader("Location", absoluteRedirectUrl);
User-agent receiving this response must do next request using the same method that was used in previous request. So if first request was POST redirected request also will be POST.

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 Protection with HTTP GET requests in 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.

Rails, REST Architecture and HTML 5: Cross domain requests with pre-flight requests

While working on a project to make our site HTML 5 friendly, we were eager to embrace the new method for Cross Domain requests (no more posting through hidden iframes!!!). Using the Access Control specification we begin setting up some tests to verify the behaviour of various browsers.
The current Rails RESTful architecture relies on the four HTTP verbs: GET, POST, PUT, DELETE. However in the Access Control spec, it dictates that non-simple methods (PUT, DELETE) require a pre-flight request using the HTTP verb OPTIONS. In addition during testing we discovered that Firefox 3.5.8 pre-flight POST requests as well.
My question is this. Is anyone aware of any project for the Rails framework working to address the issue? If not, any opinions about the best strategy to support the OPTIONS method, since it has to support the routes for all the POST, PUT, DELETE methods?
I released a Gem a couple of days ago that implements CORS support via a Rack Middleware:
http://github.com/cyu/rack-cors
Regarding preflight CORS requests, I couldn't get preflight requests working in Chrome (through simple CORS requests work fine). Searching around the Internets suggests that it might not be supported. I've asked questions in the Chrome forum about this, but haven't heard a response yet.
This is from Spine js documentation
CORs Rails integration
Let's create a cor method, which will add some of the request access control headers to the request's response.
Add the following to app/application_controller.rb:
before_filter :cor
def cor
headers["Access-Control-Allow-Origin"] = "js-app-origin.com"
headers["Access-Control-Allow-Methods"] = %w{GET POST PUT DELETE}.join(",")
headers["Access-Control-Allow-Headers"] = %w{Origin Accept Content-Type X-Requested-With X-CSRF-Token}.join(",")
head(:ok) if request.request_method == "OPTIONS"
end
Although Access-Control-Allow-Origin takes a wildcard, I highly recommend not using it as it opens up your app to all sorts of CSRF attacks. Using a whitelist is much better and more secure.
The Access-Control-Allow-Headers section is important, especially the X-Requested-With header. Rails doesn't like it if you send Ajax requests to it without this header, and ignores the request's Accept header, returning HTML when it should in fact return JSON.
It's worth noting that jQuery doesn't add this header to cross domain requests by default. This is an issue that Spine solves internally, but if you're using plain jQuery for CORs, you'll need to specify the header manually.
jQuery.ajaxSetup({
headers: {"X-Requested-With": "XMLHttpRequest"}
});
Some browsers send an options request to the server first, to make sure the correct access headers are set. You'll need to catch this in Rails, returning a 200 status with the correct headers. To do this, add the following to your application's config/routes.rb file:
match '*all' => 'application#cor', :constraints => {:method => 'OPTIONS'}
That's it, you're all set up for Cross Origin Requests with Spine!
I hacked rails to support the options method. I posted this on the rails list, but it never made it past the list.
GitHub Gist: Rails XHR2 / CORS / OPTIONS support
ctrl+f to find the lines that have #Options - those are the only ones I changed.
And here's an example implementation | and another

Resources