CORS policy in node.js doesn't update headers - node.js

I have two websites build in angular, one in the main domain and another in a subdomain. Both of these applications interact with a node.js application. The node.js app is using the cors package allowing requests from both urls, the problem is if i am in the subdomain and access some routes from the main domain app i get the cors blocked error but the origin i am receiving is the subdomain one (apparently). This also happens the other way around.
Example:
I access example.com/xyz and it works, then i go to the subdomain asd.example.com and get the cors error because the origin it receives is example.com.
Then if i clean the cache i can access asd.example.com but then i have the error on some routes in example.com and in this case the origin is asd.example.com.
One of the routes i have on the main application has the same name as the subdomain, is there any chance the issue is caused by this?
[edited]
This is my node.js cors code.
The allowedOrigins variable is an array with all allowed urls, e.g var allowedOrigins = ['https://example.pt', 'https://www.example.pt', 'https://asd.example.pt'];
app.use(cors({
credentials: true,
origin: function(origin, callback){
if(allowedOrigins.indexOf(origin) === -1){
var msg = 'Blocked by CORS';
console.log(msg);
return callback(new Error(msg), false);
}
return callback(null, true);
}
}));
Regarding my initial question i have already tried to change the subdomain name to something different than any route in main app.

Related

How to prevent ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep?

I am attempting to access my movie API that returns data including an image of a movie poster through a React application. This image is being requested from an external website. Each time I make a request to my \movies endpoint, the image is blocked and I get the following message in the console
net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep 200
When looking at the request in the Network tab, I get the following message saying to enable a Cross-Origin Resource Policy
Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each resource must specify a suitable Cross-Origin Resource Policy (CORP). This behavior prevents a document from loading cross-origin resources which don’t explicitly grant permission to be loaded.
To solve this, add the following to the resource’s response header:
Cross-Origin-Resource-Policy: same-site if the resource and your site are served from the same site.
Cross-Origin-Resource-Policy: cross-origin if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.
I am using the CORS npm module which had previously been used to solve my issue with an Access-Control-Allow-Origin error. I added some additional middleware to try and add the header as instructed. This is the app.js server with that code
App.js
'use strict';
import express, { json, urlencoded } from 'express';
import morgan from 'morgan';
import mongoose from 'mongoose';
import passport from 'passport';
import cors from 'cors';
import dotenv from 'dotenv';
import auth from './routes/auth.js';
import routes from './routes/routes.js';
dotenv.config();
const app = express();
mongoose
.connect(process.env.CONNECTION_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(res => console.log('DB Connected!'))
.catch(err => console.log(err, err.message));
app.use(cors())
app.use((req, res, next) => {
res.header("Cross-Origin-Resource-Policy", "cross-origin")
next()
})
app.use(passport.initialize());
app.use(json());
app.use(urlencoded({ extended: true }));
app.use(express.static(`public`));
app.use(morgan('common'));
auth(app);
import './authentication/passport.js';
routes(app)
app.use((req, res, err, next) => {
if (err) {
console.error(err.stack);
res.status(500).send('Something broke!');
}
next();
});
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => console.log(`Listening on Port ${port}`));
After doing this, the console throws the same error and the Cross-Origin Resource Policy still is not set. Is there something wrong with my approach or the way that I have my file structured?
You have COEP enabled in the client:
Cross-Origin-Embedder-Policy: require-corp
This is a great security feature that means:
COEP: Everything (data, images etc) on this website is mine, or I fetch from it from other websites using CORS. (There can be a third way, that is data being authorized by cookies, http-auth, etc... which is not in our discussion, so don't bother here.)
So, you have two options. The first one is to disable COEP, but I assume that you don't want to do that. So, the other option is to use CORS for everything external. For example, when you fetch something, use:
fetch('https://externalwebsite.com/image.jpg',{mode:'cors'})
or, to embed an external image in the HTML, use crossorigin
<img crossorigin="anonymous" src="https://externalwebsite.com/image.jpg">
Note that crossorigin attribute in <img> means CORS. If it is missing, it means "no-cors", which is the default. Be aware though: When you use JavaScript's fetch, the default is {mode:'cors'}, i.e. the opposite!
Now, if you try to do that (use CORS, as you should), the browser will throw another error:
Access [...] has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
That means... exactly that! That the external server has to send the header:
Access-Control-Allow-Origin: *
That setting means that every website can use the server's resources (API in your case), as long as it does not use/send/receive cookies in the request (because... security). The way to implement this in your express server is to set:
res.header('Access-Control-Allow-Origin', '*');
Every server that intends to serve things to other websites, must have this ACAO header. (You can place your other website instead of "*" if you want only that website to access your API.)
Note/Summary:
If the external server has this ACAO header, you can fetch things using CORS/crossorigin. If it does not have ACAO header, you can fetch things with no-cors / without crossorigin. But with COEP enabled in your website, you can only fetch with CORS/crossorigin, so the external server has to have an ACAO.
Now,
As for the Cross-Origin-Resource-Policy that your server has, have in mind that (https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)):
The policy is only effective for no-cors requests
During a cross-origin resource policy check, if the header is set, the browser will deny no-cors requests issued from a different origin/site.
This means that, since you make only CORS requests to that server, this header doesn't do anything (in your case). So the server can set it to "same-site"/"same-origin" for security reasons that are beyond this topic.

CORS Node.js in chrome browser

I am using Heroku and netlify to host
https://n-blogcode.netlify.app/
Now I m using cors in backend and it needed to be switched on using a chrome extension on my pc for the cards section to work.
But not everyone will know to enable cors access through extension to see my website. So how do I make it so everyone can directly see it
before resolving the CORS error you have to understand how it works, quoted by IBM.com:
CORS is a mechanism that uses additional HTTP header to inform a
browser to allow a web application running at one origin (domain) have
permission to access selected resources from a server at a different
origin
consider an API which is for ABC Bank, a hacker want to send some request to this API but with your account, if CORS does not exist, the hacker simply could write a malware code something like this:
Axios.post("https://bankABC.com/api/MoneyTransfer?to=123456789");
and puts this script on a third-party website.
when you open that site, the hacker can steal all your money!
but fortunately, the CORS mechanism was implemented in our browsers to prevent such undesirable cross-domain requests, to define which origin can send requests to a special route, you have to set that in the Access-Control-Allow-Origin header in your response header. there is a middleware called cors, which you can use to define this header...
Use the npm cors package in your nodejs program, and place your netlify origin on the allowed list.
Something like this might work.
const express = require('express')
const cors = require('cors')
const app = express()
var corsOptions = {
origin: 'https://n-blogcode.netlify.app'
}
...
app.use(cors(corsOptions)) //cors for all routes
app.options('*', cors()) //cors for preflight requests
This causes your nodejs program to include the appropriate CORS headers in its responses to requests from your html / js code hosted on netlify.
You definitely don't want to require a web extension for your users. If you do, you won't have many users. :-)
If you're want to handle multiple origins:
let whitelist = [
process.env.WEB_URL,
process.env.ROOT_API,
process.env.SOCKET_URL
]
let corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Origin not allowed by CORS'))
}
}
}
app.use(cors(corsOptions))

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
}))

How to call microservice (built in express js) from angular app which is already calling sails js backend?

I already have an application with angular front end and sails js backend. But due to some reason I moved some backend functions in seperate express project like micro-service. But Now I want to call those functions. Kindly tell me how to do this.
There are two ways to do this:
CORS
Your microservice should enable cors so that the browser doesn't block its responses. In Express this can be as simple as:
const cors = require('cors');
app.use(cors());
Depending on weather the endpoint requires credentials (login) you may have to set a few options for cors:
app.use(cors({
credentials: true,
origin: true,
methods: 'POST,GET,PUT,OPTIONS,DELETE'
}));
see my answer to this other question: Node.js with Angular - CORS error when i send request
Check out the documentation of the cors middleware for configuration options: https://www.npmjs.com/package/cors
Application Gateway
You can also run all your microservices behind a reverse proxy such as Nginx or Apache2 or HAproxy. This strategy is what makes Amazon work before 2014 (before browsers implemented CORS).
Here's a simple example of an Nginx configuration for proxying your microservice:
# The ^~ operator matches all urls that begins with the following string:
location ^~ /some/microservice {
proxy_pass http://some.microservice.myapp.com;
}
A reverse proxy that maps multiple microservices to url paths on a single domain name is often called an Application Gateway in the industry. Application Gateways also provide additional benefits such as load-balancing, firewalling the internal servers form the internet etc. But for our purposes the main reason to use it is to allow microservices to be served form the same domain as your front-end code which means making requests to microservices does not trigger cross-origin policy.
Either way, to request data from your microservices you'd just make an ajax request. Either via old-school XMLHttpRequest or the more modern fetch API:
// Assuming you've configured CORS correctly on your server:
fetch('https://some.microservice.myapp.com/getdata')
.then(function(response) {
return response.json();
})
.then(function(result) {
console.log(result);
});
// Assuming you are using an application gateway:
fetch('https://myapp.com/some/microservice/getdata')
.then(function(response) {
return response.json();
})
.then(function(result) {
console.log(result);
});

CORS-enabled server not denying requests

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

Resources