Force SSL with expressjs 3 - javascript

I'm running a node.js express 3 server with no proxies and using SSL.
I'm trying to figure out how to force all connections to go through https.
Google searching shows me this:
https://groups.google.com/forum/#!topic/express-js/Bm6yozgoDSY
There's currently no way to force https redirects, though that seems
like a bit of a strange work-around. We have an https-only app and we
just have a simple ~4 line node http server that redirects, nothing
fancy
Which is what I need, but he doesn't say what those 4 lines are.
How do we do this? Thanks.

I don't really understand the point in starting two servers when only one can do the job perfectly. For example, by adding a simple middleware in your server file:
app.use(function(req, res, next) {
if(!req.secure) {
return res.redirect(['https://', req.get('Host'), req.url].join(''));
}
next();
});
This will redirect any non-secure request to the corresponding HTTPS page. For example, http://example.com/ to https://example.com/ and http://example.com/foo?bar=woo to https://example.com/foo?bar=woo. This is definitely the behavior I would expect. Maybe you should filter this by host, so it redirects only on domains for which you own and installed a proper certificate.
If your app is running behind another server like Nginx, you may want to add the configuration parameter app.set('trust proxy', true). Or, even better, make Nginx do the redirect itself, which will be more efficient than any Node.js app.
Edit: According to my benchmarks, join is a little faster than + for concatenating strings. Nothing dramatic, but every win is a win...

You should create a second server listening on 80 and redirect with a 301 header to your https server:
var express = require('express');
var app = express();
app.get('/', function(req, res, next){
res.redirect('https://' + app.address().address)
});
app.listen(80);

I had a similar problem and the redirect solution is not suitable for me because essentially I want to get rid of the browser's insecure warning,
So instead of redirect every message, I did:
app1 = new express()
app1.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/redirect.html'));
});
app1.listen(80, function(){'redirect server running on 80 port'})
and in the redirect.html is just a redirecting html file:
<meta http-equiv="refresh" content="0; URL='https://my-site.com'" />
Of course, this won't work for complicated cases when you want to redirect all routings, but for me, I only want to redirect my homepage to my https homepage and get rid of the browser's insecure warning. Hope this help somebody!

Related

res.redirect() not working properly in express JS

I've been working on creating an API for a blockchain I've made.
Everything was going fine, until I updated Node and Windows...
====== ISSUE ======
After performing a POST request, I cannot redirect to a GET page anymore. (Using Postman only no front end yet).
For some reason, it was working fine and now I can't do it in a simple test file even.
I've attached the simple express test file below (which duplicates my problem).
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello World from GET!");
});
// BELOW IS THE WAY I'VE WORKED AROUND IT FOR NOW
// app.post("/", (req, res) => {
// res.send("Hello World from POST!");
// });
app.post("/me", function (req, res) {
res.redirect("/"); // ISSUE HAPPENS HERE
});
var server = app.listen(8081, () => {
var port = server.address().port;
console.log(`Example app listening at http://localhost:${port}`);
});
Using PostMan, now whenever I try to redirect after app.post("/me"), it will return a 404 error shown below...
<body>
<pre>Cannot POST /</pre>
</body>
I found out if I add a POST method to the "/" route (commented out above), it will work correctly.
Why didn't I have to do this before??? Did I break my computer? lol
I have tried uninstalling Node v19 and reinstalling Node v16. (no change)
I uninstalled the Windows updates that I did when restarting for Node v19 installation.
Your browser makes a POST / request after redirection, which your app does not accept, it expects a GET / request instead.
Whether a redirection after a POST request leads to a GET request or another POST request depends on the HTTP status (between 301 and 308) as well as on the browser. Perhaps the Windows update changed the default behavior of your browser?
To avoid any ambiguity, you should use
app.post("/me", function (req, res) {
res.redirect(303, "/");
});
See also Google Apps Script return 405 for POST request.
I deactivated "Follow original HTTP Method" in PostMan request settings (near body and headers).
This solved my problem. PostMan was executing another POST request on my redirect, instead of a GET.
Following the link Heiko provided above, and another link on that page about changing PostMan settings, led me to this page...
https://makolyte.com/postman-follow-redirects-with-the-original-http-method-and-content-type/
I was able to disable the "Follow original HTTP Method" which will "Redirect with the original HTTP method instead of the default behavior of redirecting with GET" while it is activated.
It appears this is a per request change in PostMan however.
Not sure exactly what caused this to happen, but it works!
I also found out about the PostMan console, located at the bottom of the screen. This was helpful in debugging the issue.

Why am i getting the output twice in the Node console?

I have just started learning NodeJS, Kindly help me understand this
const http = require('http');
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('In the Middleware');
next();
});
app.use((req, res, next) => {
console.log('In another Middleware');
res.send('<h1>Hello From Express</h1>');
});
app.listen(3000);
Output is
In the Middleware
In another Middleware
In the Middleware
In another Middleware
Expected
In the Middleware
In another Middleware
Browsers will often make multiple requests to a server. For example, they will usually try to fetch a favicon.ico file. Another example is a CORS preflight request.
If you open the developer tools in your browser, go to the Network tab, and then refresh your page, you will see all the requests the browser makes (you may need to check the "Disable cache" checkbox first). If you see more than one request, that's probably the reason you're seeing your text logged multiple times.
Another simple way to test this is to try making a request to your server from a client other than your browser. For example, run this from the command line: curl http://localhost:3000. That command should make only a single request to your server. Do you see your text output multiple times in that case? If not, then that's further evidence your browser is making multiple requests to your server.
I would say that this happens because the browser usually makes a request for the favicon.ico as well, but you can check in the Network tab of the developer tools.
In my case, i was using:
app.use('/',function(req,res){
console.log('here');
})
So, I though whenever I refresh my frontend this should run once. But, browser actually sends multiple request whenever you refresh. (i.e favicon)
That's the reason your code logging multiple times.

Issue with document.cookie: Works in localhost but Returns Empty on Web Hosting

I've been searching lots and lots of sources but does not seem like anything describes my case.
I am currently trying to develop a website (ReactJS) and a back-end (NodeJS w/ Express). Let's say they are accessible at example.com and example.com/api respectively on production, and then localhost and localhost:3030 on development. The cookies are set by the API.
Entering alert(document.cookie) into my browser's console on my local machine outputs my non-HTTPOnly cookies. However, when I tried this on my web hosting, it only returns an empty alert box, which indicates that document.cookie is an empty string "". This was tested on Opera, Firefox and Chrome.
I also have already tried unsetting HTTPOnly and secure flag for my session cookies from my Node app but this too is not written into the alert output.
Does anyone here know why this happens and/or how to make this work? Thanks!
EDIT: Here's how I set my cookie on the NodeJS
app.use(function (req, res, next) {
res.cookie("My-Cookie", random());
next();
})
EDIT2: I guess this is an issue with how CORS actually work. But I still don't get why my localhost version works even though it's also CORS.
Turns out this issue is regarding the Set-Cookie domain. First, my cookie was set for www.example.com while I open example.com in my browser. Second, I fixed this problem by specifying {domain} option on ALL my cookie settings including the cookie generator like so:
app.use(function (req, res, next) {
res.cookie("My-Cookie", random(), { domain: '.example.com' });
next();
});
Now I can open either www.example.com or example.com and document.cookie returns the cookie values as intended.
Hope this helps anyone out there who are not aware of this limitation.

NodeJS, Express, why should I use app.enable('trust proxy');

I was needed to redirect http to https and found this code:
app.enable('trust proxy');
app.use((req, res, next) => {
if (req.secure) {
next();
} else {
res.redirect('https://' + req.headers.host + req.url);
}
});
I'm using heroku to host my project, I noticed that heroku as default issued *.herokuapp.com cert, so I can use http and https as well.
When looked at req.secure within app.use callback, without app.enable('trust proxy'), req.secure is always false, when I add app.enable('trust proxy') it's false for about 2 times and after the https redirection it's switches to true.
app.enable('trust proxy'), the docs:
Indicates the app is behind a front-facing proxy, and to use the
X-Forwarded-* headers to determine the connection and the IP address
of the client.
My question:
Why would my server be behind a proxy?(is it relates to the issued *.herokuapp.com cert?), if someone could explain how all fits together, I mean, why my server is behind a proxy? and why without app.enable express won't identify(or accept) secure connection?
If your not running behind a proxy, it's not required. Eg, if your running multiple websites on a server, chances are your using a Proxy.
X-Forwarded-For header attributes get added when doing this so that your proxy can see what the original url was, proxying in the end will be going to localhost you see. The reason why it's needed is that X-Forwared-For can be faked, there is nothing stopping the client adding these too, not just a proxy. So trust-proxy should only be enabled on the receiving end, that would be behind your firewall. Because you have control, you can trust this.
So in a nutshell, if your website is running behind a proxy, you can enable it. If you website is running direct on port 80, you don't want to trust it. As the sender could pretend to be coming from localhost etc.

Create/configure node.js dispatcher/proxy

I'm working on javascript Single Page Application with Aurelia framework and using simple fake backend(express.js) for prototyping purposes.
Backend runs on localhost:8081 and client app on localhost:9000
There are some Cross Domain issues because these are different ports, and adding cross origin headers to the backend seems cumbersome to me.
What i want is simple dispatcher/proxy that would run on, say, localhost:3000 and redirect incoming calls in this manner (localhost:3000/app => localhost:9000) (localhost:3000/api => localhost:8081) Thus eliminating cross domain issues.
I'm looking for really simple solution, maybe there is some node.js app that suited just for such cases.
If you are using Express, you can add this routes to your app.
You need to install the module 'request' for this example
// At the top
var request = require('request');
And then:
//APP
app.use('/app', function (req, res) { request('http://localhost:9000' + req.originalUrl).pipe(res); });
//API
app.use('/api', function (req, res) { request('http://localhost:8081' + req.originalUrl).pipe(res); });

Categories