How do I manage API (HTTPS) certs in DEV vs PROD in express on a node/ angular environment deployed to Windows IIS? I've seen proxy rewrites mentioned on this but I'm not sure how it is managed on express side.
I know in PROD, IIS and rewrites in web.config help manage cert for front end, but most of the tutorials I see for https on express require hard coding a self signed cert and including it in build. In PROD I have an official signed cert on server that I will use on port 8443 and not sure how that changes code, see below:
const express = require('express')
const app = express()
const https = require('https')
const fs = require('fs')
const port = process.env.PORT || 8443;
app.get('/', (req, res) => {
res.send("IT'S WORKING!")
})
const httpsOptions = {
key: fs.readFileSync('./security/cert.key'),
cert: fs.readFileSync('./security/cert.pem')
}
const server = https.createServer(httpsOptions, app)
.listen(port, () => {
console.log('server running at ' + port)
})
On a separate, but related note, how does my API service in Angular change to call the backend API for Dev vs PROD. I'm guessing something like this which IIS would re-route to PROD domain?
private API_URL: string = 'https://localhost:8443/api/';
I've seen proxy rewrites mentioned on this but I'm not sure how it is
managed on express side.
It does not need managed on express side. Express does not need to know about the certs that IIS injects.
In PROD I have an official signed cert on server that I will use on
port 8443 and not sure how that changes code
Express does not need cert in prod, IIS bindings handle that. So in server.js code only include httpsOptions if on dev and inserting self signed cert.
On a separate, but related note, how does my API service in Angular
change to call the backend API for Dev vs PROD. I'm guessing something
like this which IIS would re-route to PROD domain?
Angular CLI should provide you an environments folder with environment.prod.ts and environment.ts files which will swap the variable values they hold based on build type. Simply add a variable in both for different urls for express to call when sending requests. Your prod url will not be localhost and instead should be the actual url the user will access in production.
Related
all my servers are hosted locally. I use IIS on server 2019 to host and manage my website. I use NodeJs to act as an API which makes queries to my SQL server to get the information and return it to my React app.
my react app calls out to my NodeJs API using fetch url
var url = 'https://example.com:8080/api/locationInfo/client?client=%';
fetch(url, {agent})
.then(response => response.json())
.then(data => setLocationInfoData(data));
since my website is using HTTPS, i must use that in the URL that reaches out to the API service from NodeJs.
right now when i attempt to make these API calls, console is giving me the error: net::ERR_SSL_PROTOCOL_ERROR
im assuming this is because my NodeJs app does not have an SSL certificate installed.
I've spent many (many) hours of research, but im not experienced with the backend of web development and im having trouble understanding where and how i apply an SSL cert to my NodeJs API. I used IIS to create a self-signed certificate, but it hasnt been applied anywhere and nothing else was done; im not sure where to go from here.
if it matters, my NodeJS API is hosted on the C:\Program Files[...] directory of the server, not under the actual web hosted directories.
If i place the NodeJs app within the actual web hosted directories, would i still need a certificate? If so, how do i export the .key and the .crt files to include in my NodeJs code?
please let me know if i can provide any more information or any of my code. My experience is limited, but im determined to learn and just need some pointers to send me in the right direction.
EDIT: i created a PFX cert from windows and used openSSH to convert the key, ca, and cert to .pem and included those in my nodeJs application. now im getting "ERR_SSL_KEY_USAGE_INCOMPATIBLE"
nodeJS code:
const sslServer = https.createServer(
{
key: fs.readFileSync(path.join(__dirname, 'cert', 'key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'cert', 'cert.pem')),
ca: fs.readFileSync(path.join(__dirname, 'cert', 'ca.pem')),
},
app
)
! I have implemented a WebApp and SQL-DB.
added custom domain and SSL certificates (which bought at CA).
for SSL offloading purpose we configured an azure application gateway.
with all setup.
next, we configured azure traffic manager so that traffic manager decide active web app routing.
our concern is when I adding the CNAME record for traffic manager in GoDaddy it is routing to WebApp, everything is great.
but when I search "xxxx.com" Digwebinterface it shows all connections to WebApp
in this, I took the traffic manager CNAME record and added to another domain then the duplicate domain also accessing all my content of the website and even create a record in SQL also.
in this scenario I losing my website restriction unauthorized domain can map site
any suggestion and insights it would be grateful to
thank you
The simple way is to create a filter in your code for inspecting the host of headers of request to allow or deny the accessing from different domain.
Here is my sample code in Node.js with express.
const express = require('express')
const app = express()
const port = 3000
const allowedHosts = [`localhost:${port}`]
var domainFilter = function(req, res, next) {
if(allowedHosts.includes(req.headers.host)) {
next()
} else {
res.status(403).end()
}
}
app.use(domainFilter)
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
It will allow the request from localhost:3000 and deny the request from 127.0.0.1:3000 or others, as the figures below.
Fig 1. Allow the request from localhost:3000
Fig 2. Deny from 127.0.0.1:3000 or others
Hope it helps.
I've read a tonne of articles on the web and looked at a tonne of questions on stack overflow related to the following, and they all provide basically the same solution which I am unable to implement due to security issues with my company.
I am trying to deploy a NodeJS app to a secure windows server without IIS. I'm not even sure if this is possible - there is very little support about deploying node apps to windows, and what support there is says to use IIS and iisnode together. To add to the complication, my company will not give me the key to the main SSL certificate of the server.
I have access to the server/cert store/certificate, but I can't export its key. Just wondering if there is a way to have server.js point to just the certificate instead of both the certificate AND the key?
I've tried to access the certificate and extract the key via https://www.npmjs.com/package/win-ca but haven't had any luck with this.
I was able to use a self-signed certificate and get everything working, but you need to accept the self-signed certificate in your browser which isn't a viable solution for production.
I've also looked into using nginx, let's encrypt, etc., but windows support for those isn't that great either.
Here is my code which works, but like I said, I need to accept the self-signed cert client side which isn't ideal:
const express = require('express');
const app = express();
const https = require('https');
const http = require('http');
const fs = require('fs');
const options = {
//self-signed cert, I'd rather point this to the main cert for the server
//but I don't have access to the key
key: fs.readFileSync('cert.key'),
cert: fs.readFileSync('cert.pem'),
};
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
app.get('/', function (req, res) {
res.send('Hello World!');
});
In the end I removed all the certificate and security related stuff from my server.js file and just put the website behind a load balancing proxy server.
I have a Node/Express app running on a server with https enabled but when trying to login with Facebook using Passport Facebook strategy, I get this error:
Insecure Login Blocked: You can't get an access token or log in to
this app from an insecure page. Try re-loading the page as https://
I understand Facebook requires authentication but my server already has it.
The certificate is from LetsEncrypt and since I'm using a managed server, I don't have access to the certificate files. My Express app is initialized normally.
const app = express();
const cors = require("cors");
app.use(cors({ origin: true, credentials: true }));
The original request comes from my frontend running on a different server, also with SSL from LetsEncrypt.
So my front end calls the Express endpoint, which handles it to Passport:
app.get(
"/api/auth/facebook",
storeRedirectToInSession,
passport.authenticate("facebook", { scope: ["public_profile", "email"] })
);
And then the error occurs.
My research indicated that enabling "trust proxy" on Express should fix it but it didn't. If I inspect req.secure it's always false.
Do I really need to have access to the certificate files?
Any help is appreciated.
Thanks
People of the future, I could not fix this issue without actually getting access to the cert files on my Node/Express app. I had support create symbolic links to the letsencrypt key and cert files, and then created a https express server as follows:
https
.createServer(
{
key: fs.readFileSync(keys.SSL_KEY_FILE),
cert: fs.readFileSync(keys.SSL_CERT_FILE),
},
app
)
.listen(port, function() {
console.log("ackend server listening on port ", port);
});
On the OpenShift website here: https://help.openshift.com/hc/en-us/articles/202535440-How-do-I-get-SSL-for-my-domains-, it states
You can always take advantage of our *.rhcloud.com wildcard certificate in order
to securely connect to any application via it's original, OpenShift-provided
hostname URL.
However, Node's HTTPS server requires a file path to a certificate and private key in order to use HTTPS:
var privateKey = fs.readFileSync('sslcert/server.key', 'utf8');
var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(443);
None of the OpenShift environment variables (https://www.openshift.com/developers/openshift-environment-variables) appear to be related to SSL certificates, and the documentation does not mention it other than at the above link, which provides no technical information in actually using it.
How do I access the privateKey and certificate file on an OpenShift Node.js gear/cartridge?
It turns out that all SSL certificates are handled by OpenShift routers before they reach the gear/cartridge. There is no need to setup an HttpsServer at all, the normal HttpServer listening on port 8080 will receive both HTTP and HTTPS traffic transparently.
This is true whether you are using a custom certificate or the wildcard certificate, which is pretty nifty.
Nodejs Express application scenario is detailed at OpenShift https answer. To sum up, use the X-Forwarded-Proto header's value from the request headers given to your nodejs web server by openshift's proxy to determine if reply should redirect client to https or is client already requesting on https.