CORS Node.js in chrome browser - node.js

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

Related

What is the difference between Helmet and CORS packages node.js

I'm using Helmet and CORS packages to my node.js application. But I don't know what's the difference of both packages and the performance impact to the application. Also, by using these packages, will it secure the my node.js application or adds security to the client?
Helmet is a nodejs package that helps protect your server from some well-known web vulnerabilities by setting HTTP response headers appropriately, it comes with a collection of several middleware functions that set security headers that are returned from your express application.
The top-level helmet function is a wrapper around 15 smaller middlewares.
Some security attacks help secure your express server from common attacks such as clickjacking, and cross-site scripting attacks, it also helps enforce secure HTTPS connections to your server, download options for vulnerable browsers, and a host of other vulnerabilities.
As you see it's an important package to have in your express app, it's actually listed among packages to use under production's best practices from the official express website.
Cors on the other hand is a node.js package that provides your express app with middlewares to enable Cross-origin resource sharing (CORS) which is a mechanism that allows resources on your express app from being shared with external domains, its important in making cross-domain requests possible in case it's needed.
A typical use case is developing a full-stack application where the static content like the HTML pages are not located within the domain of your express app, like in the case of local development where an angular or react app running on localhost:4200 needs to access your express app resource served from localhost:3000, without CORS enabled this request will not be possible.
The Cors package equally exposes a reach interface to restrict access of resources to whitelisted domains, below is an example from the node.js CORS package
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
Notice the whitelisted domains http://example1.com and http://example2.com allowed to access the /products/:id route of the express server.
Summary
Helmet and Cors are 2 important node.js packages with different purposes. Helmet secures your express app by setting response HTTP headers appropriately, while Cors enables your express application access control to allow restricted resources from being accessed from external domains.
Performance-wise, both helmet and cors bring basic middleware functions with little or no performance effect, setting a couple of important HTTP headers will not negatively impact your server, I don't think so. and as a matter of fact now you know the importance of using this packages in your express app and what it brings.
In my opinion CORS is the best, you can easily eliminate the worst error which is "breaking cors law", and also adding some security to your node.js application, by stricting it to accept connections from origins you want to. So, yes, it will secure your node.js app if you know how to set it right

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 policy in node.js doesn't update headers

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.

Access to XMLHttpRequest at '...' from origin 'localhost:3000' has been blocked by CORS policy

Edit
A little late, but I remember that I ended up solving this issue by setting credentials: true in my cors config on my backend.
By complete accident, I noticed that if I set credentials: false in my axios client on the frontend, everything worked fine. However, switching it to true kept throwing the error. I then put two and two together and set credentials: true on my backend and everything worked as expected.
My app used cookies, so it had to be done this way.
This may be a duplicate, but I havent found a thread relating specifically to my issue.
I am making the following API call:
const config = {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS"
}
};
const {
data: { ip }
} = await axios.get("https://api.ipify.org?format=json", config);
And this throws an error:
Access to XMLHttpRequest at 'https://api.ipify.org/?format=json' from origin 'http://localhost:3000' 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.
When I deploy my app to Heroku, the API call works as expected. However it does not work when developing on my local machine. Not sure what I'm missing here.
if you are building your rest api in nodejs. Follow the folowing simple steps
Stop the Node.js server.
npm install cors --save
Add following lines to your server.js or index.js
var cors = require('cors')
app.use(cors()) // Use this after the variable declaration
Now try to make your api call on the client side and it should work
After many days finally I got a solution . Instead of using CORS simply like this
const cors = require('cors');
app.use(cors());
in your server index.js using CORS option will solve the issue and now you can pass cookies or other credentials
const cors = require('cors');
const corsOptions ={
origin:'http://localhost:3000',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
app.use(cors(corsOptions));
You can't really fetch data from servers, with a different hostname, that don't have a CORS policy to allow request from your domain.
In simpler words, localhost can't call ipify.org unless it allows it. It seems like it doesn't, and I assume that server is not managed by you. So your only option is to go with a reverse proxy. You can read how to create an http proxy with node here.
What you need is for your app to be served on a fake/stubbed host, rather than localhost:
local.development.ipify.org -> proxies to localhost:3000
That way, when you make your api call, you are under the same domain as ipify.org, and you won't get any CORS issues.
This article solved my problem in no time.
The quickest fix you can make is to install the moesif CORS extension . Once installed, click it in your browser to activate the extension. Make sure the icon’s label goes from “off” to “on“
First of all in your back-end app like express app you have to enable cors
like :
install cors running the command npm i cors
then go to your server.js or app.js or index.js file and add
var cors = require('cors');
app.use(cors())
3.cors will enable your client or front-end app to access your back-end routes. finally go to your routes and inside get route paste the following lines
router.get("/", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "1800");
res.setHeader("Access-Control-Allow-Headers", "content-type");
res.setHeader( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS" );
});
`
I also suffered for 2 hours facing this issue and i resolved my problem like this.So hope this will help you
Go to your package.json file and add:
"proxy": "your-api-url" but only the beginning/base, as an example if you are using the pokemon api, you just have to set "proxy" : "https://pokeapi.co/api/v2"
and in your service file you can use axios with the path you need:
axios.get("/pokemon?limit=1000")
.then(response => {
resolve(response.data.results);
})
What you seem to be trying to do is telling the server that it should use the CORS policies that you have specified in your Axios call. This is simply not how things work - the server defines its own CORS policies, and you simply must conform to them. If the server that you are trying to access does not support http://localhost:3000 in its CORS policies, you cannot use that origin with the API.
If the server is yours, look into the cors package and configure it to allow localhost:3000as an origin. If you do not own the server, you can't really change any CORS policies without asking the server owner if they would be willing to do so.
This may be due to the POST request from react app in development mode. You can bypass the CORS policy in development mode by the adding following line of code in your ' file.
{
...
"proxy": "http://localhost:3000",
...
}
There may be problem with the sequence of the
app.use(corse())
you should use it before defining routes
Use below codes in your server.js or app.js or index.js file of your backend
import cors from "cors";
const corsOrigin ={
origin:'http://localhost:3000', //or whatever port your frontend is using
credentials:true,
optionSuccessStatus:200
}
app.use(cors(corsOrigin));
I was getting this issue only on crome browser and on crome browser I had multilogin extension. When I delete this extension, this issue is fixed.
always double check and make sure you're not missing a trailing slash "/" in your front-end
if that didn't solve it, you'd want to try installing CORS to you back-end by first,
pipenv install django-cors-headers
then, inside the settings add corsheaders to the installed apps as well as corsheaders.middleware.CorsMiddleware to the Middleware; if your computer didn't already.
last but not least, make sure to add CORS_ORIGIN_ALLOW_ALL = True after the ALLOWED_HOSTS.
i hope this helped (first question ever answered btw)
You have to use res.setHeader with your response
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "1800");
res.setHeader("Access-Control-Allow-Headers", "content-type");
Had this issue when sending post request from reactjs app to a django api that I manage. Solved it by installing django-cors-headers, adding core headers to installed apps, adding core headers middleware, and lastly adding the react host domain 'http://localhost:3000' into the CORS_ORIGIN_WHITELIST inside of the django settings file.
After this, my react app was able to get responses from the django api.
try to use fetch instead of Axios
return fetch(
url +
"?" +
new URLSearchParams({
email: email,
}),
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
mode: "no-cors",
}
);
If you're using axios, check out the package version.
I faced same issue when using version 1.1.x.
After change to 1.2.x, issue resolved.
"axios": "^1.2.3",

I'm getting a CORS error although Access-Control-Allow-Credentials is not set

I wrote a server app with node.js and express. The app uses the cors node package for POST requests with origin "*" because I need to be able to post from mobile apps.
Here is how CORS is enabled in the app:
var cors = require('cors');
var app = express();
app.configure(function() {
app.use(cors());
});
When I try to POST a request from a browser, I get this error:
XMLHttpRequest cannot load url. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'null' is therefore not allowed access.
However, I don't see any Access-Control-Allow-Credentials header in the response. Here is the failing request and the response in Chrome's network tab:
Why does it complain about the credentials flag?
We finally solved this. Here are our findings and the train of thought that led us to the solution:
The CORS issue happened only with POST, not GET.
The CORS issue happened only when I made the request from a local HTML whose URL starts with file://. There was no issue when I requested it from http://localhost.
When initiating a POST request from the file:// protocol, the origin is null. Turns out that the issue was that null is not covered by the wildcard *.
Setting Allow-Access-Control-Origin to null was not enough, because apparently a request from origin null includes credentials, so I had to set Allow-Access-Control-Credentials to true.
So here is my updated server code that accepts POST requests from any source, including a web view in a mobile app that works with file://:
var cors = require('cors');
var app = express();
app.configure(function() {
app.use(cors({ origin: 'null', credentials: true }));
});

Resources