Node.js CORS resulting in 403 Forbidden - node.js

Our website uses the HTML5 fetch API to make a call to our backend NodeJS service for certain actions. Our backend resides on a different domain to main website, so we have CORS enabled on the Node app. This works for 99% of our clients.
However, one client has been having issues. They are trying to access our website from their workplace (maybe their workplace network has higher security settings..?) and they're receiving the following error:
api.our-node-backend.com/blah Failed to load resource: the server
responded with a status of 403 (Forbidden) book:1 Fetch API cannot
load https://api.our-node-backend.com/blah. Response to preflight request
doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin
'https://www.our-frontend-website.com' is therefore not allowed
access. The response had HTTP status code 403. If an opaque response
serves your needs, set the request's mode to 'no-cors' to fetch the
resource with CORS disabled.
Our Node app is currently configured as follows:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
// respond to options pre-flight
app.options('*', function(req, res) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.status(200).send();
});
Is there something wrong with this configuration? Other examples on stack overflow have Access-Control-Allow-Headers set to "Origin, X-Requested-With, Content-Type, Accept" instead of just "Content-Type". What difference does that make?

Related

AWS-issued certificate failure

I have a certificate issued by AWS for my domain, and as informed I configured it on register.com. Problem is that when I open the site with www.example.com it appears as an invalid certificate, but when I open it directly with https://example.com it appears a valid certificate.
I am using NodeJS as a server, how do I redirect to always open the domain like https://example.com ?
Now is working like this:
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Locale, X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, Content-Encoding');
res.setHeader('Access-Control-Expose-Headers', 'Locale');
if ((req.headers["x-forwarded-proto"] || "").endsWith("http")) {
res.redirect(`https://${req.headers.host}${req.url}`);
}
next();
});
My certificate
You have to register your SSL certificate for both www.example.com and example.com. Registering only one, will not work because www.example.com will be considered as different than example.com.

CORS issue in API gateway lamba-proxy integration

I'm currently on a serverless application and my serverless.yml looks like
functions:
app:
handler: server.run
events:
- http:
path: /api/{any+}
method: ANY
- http:
path: /secure/api/{any+}
method: ANY
cors :
origins
- domain-url-1
- domain-url-2
As you can see above one is a secured route and that requires authorization whereas the non-secure route doesn't require any authorization headers to be passed. Since lambda-proxy doesn't take api gateway response I'm attaching the response headers on my app.js as below and for every route I'm sending the status and status codes separately in res objects.
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Request-Headers", "*");
// res.headersSent("Access-Control-Allow-Headers", "Content-Type");
res.header('Access-Control-Allow-Headers', "Origin, X-Requested-With, Content-Type, Accept, Authorization, accesstoken");
res.header('Access-Control-Allow-Credentials', true);
next();
});
But my api gateway works fine for non-secure routes while for secure routes I'm getting a CORS issue with
** Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
polyfills.ff5fcb5319b1dc651f7b.js:1 GET https://8nv8r4ph65.execute-api.us-east-1.amazonaws.com/staging/secure/api/v1/legal/notification/list?rowsPerPage=15 net::ERR_FAILED **
I'm not sure where I'm going wrong.
Your origin header does not match specified domains in ApiGateway. For fast verification remove specified domains in serverless.
This is because your secured routes are using one of the methods to pass authentication status that the browser detects as being a request with credentials. Some of the ways a browser marks a request as credentialed is if the request sends back a cookie or if the request includes the Authorization header.
Credentialed requests have an additional rule regarding CORS. The origin * is illegal for credentialed requests. Browser manufacturers instead want server admin/backend developers to tell the browser exactly what domain name is valid for the CORS request.
In addition to the rule above, list of domain names are also illegal for credentialed requests. A request with credentials can only accept one domain for CORS.
You can of course hardcode the domain name of your frontend in your server code. But this gets annoying and is not flexible in case you need to serve multiple domains.
The correct working solution for this scenario (indeed, the way CORS was intended to be used) is to check the Origin header in the request.
The laziest way to make it work is to simply copy the Origin header to Access-Control-Allow-Origin:
res.header("Access-Control-Allow-Origin", req.get("Origin"));
This will allow anyone in the world from any website to access your data. This is perfectly fine if you are OK with this and only care about using authentication to protect your data instead of also using the CORS mechanism.
If you are using the cors middleware you it will do this for you if you pass true as origin:
app.use(cors({ origin: true }));
The way CORS is intended to be used is to check the Origin against a list of approved domains:
const approvedDomains = [
"https://www.google.com",
"https://my.application.com",
"http://my.application.com" // etc..
]
function checkDomains(origin) {
return approvedDomains.filter(domain => domain === origin)[0];
}
res.header("Access-Control-Allow-Origin", checkDomains(req.get("Origin")));
Again, the cors middleware makes this simple allowing you to pass an array of approved domain names and it will do the above logic for you:
app.use(cors({ origin: approvedDomains });

Azure Functions: sudden CORS issue (after hours of copacetic development)

Getting this error "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource ..."
But I had been developing from my localhost:* just hours before. I did nothing to the application settings or CORS settings. Now I have a wildcard and it still doesn't work (above error).
I checked out {app}.scm.azurewebsites.net/Env.cshtml and I see:
...
APPSETTING_WEBSITE_CORS_SUPPORT_CREDENTIALS = True
...
WEBSITE_CORS_SUPPORT_CREDENTIALS=False
...
I don't know if these environment variables are correct or if they changed since my functions were actually working.
While I've found a solution, it probably makes sense to address this problem anyhow.
const proxy = require('express-http-proxy');
const app = require('express')();
const subdomain = '';
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:1234');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use('/', proxy(`https://${subdomain}.azurewebsites.net`));
app.listen('9091', () => {
console.log('Proxy on http://localhost:9091')
})
Then just pass in proxyUrl as a parameter if you want to preconfigure HATEOAS links.
I think that Azure App Service CORS is taking precedence over your application CORS settings. Quoting from another reply "If you enable one origin domain in App Service, and enable all domains in your Web API code your Azure API app will only accept calls from the domain you specified in Azure".
Here is the link to the other thread: Enable Access-Control-Allow-Credentials header in Azure website (Azure App Services)
I hope that you find this answer helpful :)

Express: does cors configuration depend on server TTL?

I've successfully deployed my Express API app to AWS elastic beanstalk. I have a React front end that is hosted on S3.
Both are on the same domain with the front end being at example.com & the API at api.example.com
Both have certificates and are secured.
const express = require('express');
const cors = require('cors')({
Origin: 'https://example.com'
});
// followed by required middleware
app.use(cors());
//followed by app constants
app.use((e, req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://example.com");
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if (e) {
console.log(e);
res.status(500).send(e.message);
}
next();
})
// followed by app routes
When I try and register a user on my site, I get the error:
Access to XMLHttpRequest at 'https://api.example.com/users/signup/' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This topic has of course been covered multiple times on Stack Overflow (which I've gone through multiple solutions this morning), but my question has to do with the actual server where the API is being hosted.
In the hosted zone for api.example.com, it has a TTL of 172800(48 hours). Does this mean that my changes won't be reflected in that time? If that is the case, does this mean that every time you deploy code it resets the TTL?
I'm a front end dev working on a side project, so this really isn't my area of expertise. Any DevOps or BackEnd Devs have any ideas? Thanks in advance!
In the hosted zone for api.example.com, it has a TTL of 172800(48 hours). Does this mean that my changes won't be reflected in that time? If that is the case, does this mean that every time you deploy code it resets the TTL?
No.
The TTL is how long other DNS servers are expected to cache the DNS information (e.g. which server the domain name points to).
It has nothing to do with deployment of code.
Your problem is unrelated to that. I'd add some logging to the server-side code to see which routes and middleware were actually hit as well as monitoring the precise request and response you are getting in the Network tab of your browser.
There a preflight OPTIONS request can be made by the browser for the particular types of cross-domain requests. If the response on that request is not successful or doesn't have CORS headers you will also get such error.
So I suppose that you should add a route in your Express app to handle preflight requests and send back the same CORS headers or just use express-cors-middleware.

What does cors middleware do?

Was looking at some node js code which created some web API's
and came across this:
//CORS Middleware
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With,
contentType,Content-Type, Accept, Authorization");
next();
});
Have looked around on the internet and can't seem to understand what it does?
Can someone please explain the purpose of cors middleware
This link may help.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
CORS allows you to configure the web API's security. It has to do with allowing other domains to make requests against your web API. For example, if you had your web API on one server and your web app on another you could configure CORS in your Web API to allow your web app to make calls to your web API.

Resources