CORS-enabled server not denying requests - node.js

I am trying to use express Cors with my resitfy server and it doesn't seem to be denying requests coming from other ips. I am working locally so I tried setting origin to a random public ip but all of my requests are still going through
Here is my route:
module.exports = function(app) {
var user = require('./controllers/userController');
var cors = require('cors');
var corsOptions = require('./cors.json');
app.post('/auth/signup', cors(corsOptions),user.createUser);
app.post('/auth/login', cors(corsOptions), user.validateUser);
app.post('/auth/generateKeys', cors(corsOptions), user.generateKeys);
app.post('/auth/generateToken', user.generateToken);
};
and here is my cors.json file where I have set a random ip:
{
"origin": "http://172.16.12.123",
"optionsSuccessStatus": 200,
}
With cors set on the route I can see the following in postman but the request is still going through? I would expect an access denied response.
Access-Control-Allow-Origin →http://172.16.12.123

CORS configuration on its own isn’t going to cause a server to deny requests. You can’t cause server-side blocking of requests just through CORS configuration.
The only thing servers do differently when you configure CORS support is just to send the Access-Control-Allow-Origin response header and other CORS response headers. That’s it.
Actual enforcement of cross-origin restrictions is done only by browsers, not by servers.
So no matter what server-side CORS configuration you make to a server, the server still goes on accepting requests from all clients and origins it would otherwise; in other words, all clients from all origins still keep on getting responses from the server just as they would otherwise.
But browsers will only expose responses from cross-origin requests to frontend JavaScript code running at a particular origin if the server the request was sent to opts-in to permitting the request by responding with an Access-Control-Allow-Origin header that allows that origin.
That’s the only thing you can do using CORS config. You can’t make a server only accept and respond to requests from particular origins just by doing any server-side CORS configuration. To do that, you need to use something other than just CORS configuration.

CORS does not prevent anyone from sending GET or POST requests to your application or exposed API URL.
Instead, it indicates to the web browser that AJAX requests are allowed to this server, from the domain they are executed.
But only AJAX requests executed from a domain are CORS-controlled. Entering the URL in the web browser will not activate CORS: it is not a firewall.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
The order of event is:
Domain A executes AJAX on User's browser to request API URL on Domain B
User's browser sends a basic primary request to target Domain B and checks if CORS are allowed for Domain A
If allowed, AJAX request is executed otherwise null is returned

Related

Application-wide CORS restrictions not working [duplicate]

I'd like my Rails 5 API-only app, for now running on http://localhost:3000, to only accept requests from my NodeJS front-end app, for now running on http://localhost:8888.
So I configured /config/initializers/cors.rb like this:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:8888"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
And I wrote this test:
#/spec/request/cors_request_spec.rb
RSpec.feature "CORS protection", type: :request do
it "should accept a request from a whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "http://localhost:8888"
expect(response.status).to eql(200)
end
it "should reject a request from a non-whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "https://foreign.domain"
expect(response.status).to eql(406)
end
end
The first test is passing as expected. But the second is failing with a response code of 200. Why?
(I'm not wed to a 406 response code by the way; just one that indicates the request will not be fulfilled.)
CORS configuration won’t prevent the server from accepting requests based on the value of the Origin request header. You can’t do that just through CORS configuration.
When you configure CORS support on a server, all that the server does differently is just to send the Access-Control-Allow-Origin response header and other CORS headers.
Enforcement of CORS restrictions is done only by browsers. It’s not enforced by servers.
CORS works like is: regardless of any CORS config you make on the server side, the server continues accepting requests from all clients and origins it otherwise would; and so all clients from all origins continue getting responses from the server just as they otherwise would.
So even when you see an error in browser devtools that a cross-origin request from your frontend JavaScript code failed, you’ll still be able to see the response in browser devtools.
But just because your browser can see the response doesn’t mean the browser will expose it to your frontend code. Browsers only expose responses for cross-origin requests to frontend code running at a particular origin if the server the request went to opts-in to allowing the request by responding with an Access-Control-Allow-Origin header which OKs that origin.
So for any requests with an Origin request header matching https://foreign.domain, the configuration snippet in the question should cause browsers to emit a message on the client side saying http://localhost:3000/api/v1/bodies.json can’t be loaded because there’s no Access-Control-Allow-Origin response header in the response (because your configuration causes the server to only send that header in responses to your whitelisted origins).
But that’s all you can do through CORS. You can’t prevent the server side from accepting and responding to requests from particular origins just by doing any CORS configuration on the server side. If you want to do that, you need to do it using something other than just CORS.

Socket IO allows CORS request from curl, but not from client application

I am making an application in which i have a node backend, and an angular frontend.
I am using socket.IO to communicate between my client and server.
I was facing CORS issue, which i solved (tried to) as:
const io: SocketIOServer = new SocketIOServer(server, {
cors: {
origin: true
}
}); // only for development
But still, upon making my request from my client app (running in another port) gives me CORS issue.
So i went to my terminal, and made a request with curl,as shown here:
me#Desktop:~$ curl "http://127.0.0.1:5000/socket.io/?EIO=4&transport=polling&t=NV5sBAn"
0{"sid":"jAhPIEEkdy8EY8I_AAAD","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":5000}
This suggests me that curl is being able to access the server, and is not facing CORS issue.
In my client, i am trying to connect to my server as:
socket = io.connect('http://locahost:5000'); // server running at port 5000
Help me with my issue, so i can connect with my server.
Also on a sidenote: If the version of server.io in the app is 3, the curl request to the server is also failing. only upon server.io version 4, the curl request is passing.
The error in firefox if that helps:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://locahost:5000/socket.io/?EIO=4&transport=polling&t=NV5vi1_. (Reason: CORS request did not succeed).
EDIT: my issue is not being able to connect to the server with client. I showed the curl because it was suggested in the socket.io cors configuration webpage.
Because socket.io initiates its connection with plain http requests, it is subject to CORs restrictions. CURL does not enforce CORs restrictions (like the browser does) so that's why you don't see it there.
You have a couple options:
You can enable this specific CORs request in your server to permit it.
You can specify the {transports: ['websocket']} option for your socket.io connection in the socket.io client code that initiates the connection. This will tell socket.io to immediately start with a webSocket connection which is not subject to CORs.
Curl does not implement CORS security restrictions, thus it will always be able to connect. You have different ports for your frontend and backend which are considered different CORS origins. So you either need to set your allowed origins correctly on your server and make sure it handles the pre-flight requests, or have the process serving your frontend proxy requests to the backend so that everything is on the same url from the browser’s point of view
Apprrently, the issue was:
socket = io.connect('http://localhost:5000');
changing this to:
socket = io.connect('http://127.0.0.1:5000');
worked!! I have no idea why this name was not getting resolved!!

CORS issue in Node/Express if we remove www prefix

We have a NodeJS/Express server that loads an HTML5 game we have stored on service outside of our server (think Amazon S3). The game must talk to our stats backend still on our NodeJS/Express server, but since it's on a different domain from the game that's running we encountered CORS issues. We fixed this by using the Node cors module and doing this with our route:
router.put("/stats/", cors(), async (req, res) => {
...
All has been fine, but we just learned if you visit our website WITHOUT the www prefix it still gives a CORS issue. As in if you visit us at www.example.com everything works, the game loads, and it can report stats back. But if you visit us at example.com then the game still loads, but it's giving this error:
Access to XMLHttpRequest at 'https://www.example.com/api/stats/' from origin 'https://example.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.
From what I understand, how we're using the cors package it should enable all cors requests on that route. So why is it blocking this one?
Well no one ever responded, but we've managed to solve this just by using a 301 hostname redirect. Still not sure why CORS isn't working, but this fixes our specific issue.
If you are using cors lib from nodejs.
You can make a configuration for cors to support both domains.
As an example:
const cors = require('cors')
//cors config
app.use(cors({
origin: ['https://example.com', 'https://www.example.com']
methods: "GET, POST, PUT, DELETE",
optionsSuccessStatus:200,
credentials: true
}))

Cross-Origin HTTP Request originating from server-side NodeJS/Axios/JSDOM

I am using Axios to create a HTTP request to a API server in different domain.
The API server allows Cross-Origin requests from http://localhost:3000.
I have no control over the API server.
My app usually runs in http://localhost:3000 and makes requests from browser.
There's no problem up to this point. Cross-Origin requests are working fine. However, recently I want to add a unit test for those API calls. This test environment is jsdom since I'm using Jest. This raises a problem when I create HTTP request from server-side, the origin is set to http://localhost, which the server does not allow.
The request is made using Axios:
axios.post(`${API_DOMAIN}/member/account/login`, {
username,
password,
}, {
headers: {
Origin: 'http://localhost:3000'
}
})
However, the response still says that
error: Cross origin http://localhost forbidden
How to change the "Origin" of the HTTP request I create with Axios under jsdom to other than http://localhost? I need it to be http://localhost:3000 so that the API server allows me.
It turns out jsdom is the one who makes the origin localhost, and prevented cross-origin requests. From https://github.com/axios/axios/issues/1180 I was able to solve my problem. In the test suite, place this code before any HTTP requests by axios:
axios.defaults.adapter = require('axios/lib/adapters/http')
This will make Axios use NodeJS's HTTP adapter instead of JSDOM's XMLHttpRequests. This way there will be no Cross-origin problem.
Supplimenting #Arkross answer,
axios/lib/adapters/http is not exposed by the package.
Instead, you can do this:
axios.defaults.adapter = 'http'
// or
axios.request({
adapter: 'http',
...
})

Why do I get CORS error when I make axios request based on DynDNS url name and not with IP?

I have a Raspberry with Node.js running on it. CORS is installed and configured. I've set up port forwarding but because the IP keeps changing, I registered at a DynDNS provider.
I use React.js with Axios for API requests on localhost:8080.
Interestingly, if I base my requests on (e.g.)
const ROOT_URL = 'http://81.23.563.80:5000/';
which keeps changing every 24h, then the CORS module is doing it's job and I can perform my requests. But if I want do it right and make my request to
const ROOT_URL = 'http://mydyndnsurl.provider.com/';
then I would get he typical error message:
XMLHttpRequest cannot load http://mydyndnsurl.provider.com/. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8080' is therefore not allowed
access.
Does anyone have a solution for this issue?
You still need to include the port number in ROOT_URL:
const ROOT_URL = 'http://mydyndnsurl.provider.com:5000/';

Resources