Heroku http to https forwarding issue - node.js

Using Node/Express in a Heroku hosted app. I have an http to https forwarding function, which had worked but no longer.
I had forwarding working with the following from my app.configure('production'...:
app.configure('production', function() {
return app.use(function(req, res, next) {
if (req.header('x-forwarded-proto') !== 'https') {
return res.redirect("https://" + (req.header('host')) + req.url);
} else {
return next();
}
});
It worked, I was satisfied and moved on to implement Redis-to-go instead of MemoryStorage and then to implement csrf middleware. Both of those features are working but now I'm finding that I can access my app through http://... whereas before that would have been caught and auto-forwarded to the https://... and the friendly green padlock.
Any idea what could have gone sour in the interim?

Self-answer:
Somewhere during the csrf implementation process, I made the following change to my app.configure section:
app.use(app.router);
I'd read this usage in the csrf demonstrations. But I don't know if it's necessary. Csrf middleware functionality seems un-affected when I commented that line out, and the Heroku redirect works as before.

Related

How to enable URL routing in Node and Elm application (Heroku)?

I have an elm application running on Heroku.
I didn't want to use a third party elm buildpack, so I compiled the elm files locally and pushed elm.js onto the Heroku server.
My application is using Node.js backend so I'm using this code in expresss to
serve index.html:
if(process.env.NODE_ENV === 'production') {
app.use(express.static('client'));
app.get('*', (res:any) => {
res.sendFile(path.resolve(__dirname, 'client', 'index.html'));
});
}
I can go to the heroku URL and everything works perfectly. If I click on the internal /login link, I'm redirected to the login page and my url changes to ww.mywebsite.com/login. Internal routing is not my problem.
This is my problem: Although internal routing works, if I were to manually write www.mywebsite.com/login in the navigation bar, instead of seeing the login page, I see Internal Server Error
How do I fix this? Would I need a heroku buildback to accomplish this?
As #kaskelotti from the comments pointed out, Internal Server Error was printing because the files were being found, but another error was happening once they were found. If the files had not been found I would have received a 404 error.
This was a syntax error in my express code that matched all requests with my static index.html file.
The code posted in my question is wrong, THIS is how it should look:
if(process.env.NODE_ENV === 'production') {
app.use(express.static('client'));
app.get('*', (req , res) => {
res.sendFile(path.resolve(__dirname, 'client', 'index.html'));
});
}
The difference is the argument to the callback function in app.get. Originally it was (res) instead of (req, res), so the res variable was mistaken for an object of type Request and not Response, since it was the first argument.
Also as #kaskelotti pointed out, Heroku is irrelevant to this problem.

too many redirects in express

I want to handle all my cookies and session stuff in a function then redirect to the destination path. I use this function in Express:
app.all('*', function(req, res, next){
if('_id' in req.session)
next()
else if('userInfo' in req.cookies){
req.session._id = req.cookies.userInfo._id
next()
} else {
res.redirect('../login')
}
res.end()
})
but browser print this error:
net::ERR_TOO_MANY_REDIRECTS
what's the problem?
This error occurs when a web browser is redirecting you to another web page which then that web page redirects you back to the same browser again. Your configurations are wrong. app.all('*', ..) runs again and again whenever a request is made, which causing repetition.
You need to have better configurations than app.all(*..) //all. You need to specify it more so that it doesn't repeat itself.
I would say limit it down to some urls and not all of them. You could do
app.get('/cookieCheckerPage', function(req, res){
//code here
});
Also please see Error 310 (net::ERR_TOO_MANY_REDIRECTS):

Disable HTTP completely in Heroku

We have a node.js express application running in Heroku. It handles authentication and has to be a highly secure.
We have forced redirect to HTTPS when we get HTTP request. But this does not seem to be enough. With tools like sslstrip we can POST via HTTP.
The only solution at hand seems to be disable the HTTP completely on Heroku.
How to do that? Is there any other suggestions?
According to OWASP you should not redirect from HTTP to HTTPS. See https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-REMOVED-_Do_Not_Perform_Redirects_from_Non-TLS_Page_to_TLS_Login_Page for more details.
I think the better solution would be to reject the request with a message letting the user know why. You should be able to do this in a middleware function. The actual status code you return is debatable but something like this should work:
app.use(function(req, res, next) {
if(req.protocol !== 'https') {
return res.status(403).send({message: 'SSL required'});
}
// allow the request to continue
next();
});
You can test whether a request used https and then force a redirect using https if that is required (note the concern pointed out by #Ryan about redirecting and security). With Heroku, you can check the req headers' x-forwarded-proto header to make sure it is https. Here is an example:
var express = require('express');
var env = process.env.NODE_ENV || 'development';
var forceSSL = function (req, res, next) {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(['https://', req.get('Host'), req.url].join(''));
}
return next();
};
var app = express();
// in your app-level configurations
if (env === 'production') app.use(forceSSL);
Note: the Heroku load balancers are determining the x-forwarded-proto header before it hits your app.
Also: get an SSL certificate if you are using a custom domain with Heroku
We've used express-sslify npm package. Added
app.use(enforce.HTTPS(true));

req.session often undefined in a route (connect-redis used as store)

The problem is the following: On the deployed nodejitsu app, often (not always!), when I redirect from the browser (clicks on a a href="/logout") to the /logout route, i get a req.session undefined within that route.
app.get('/logout', function(req, res){
log.debug("session", req.session); //undefined
});
The requests go through the following stack of 'middleware':
var store = new db.store({client: db.client}); // no problems here, redis monitor confirms
app.configure(function(){
[...]
app.use(express.cookieParser("XXXpassXXX"));
app.use(express.bodyParser());
app.use(express.session({
secret: "XXXpassXXX",
store: store
}));
app.use(function(req, res, next) {
var fullURL = req.protocol + "://" + req.get('host') + req.url;
if (fullURL.indexOf("logout") != -1 || fullURL[fullURL.length-1] == "/") {
log.debug(fullURL);
log.debug("sesiune", JSON.stringify(req.session)); // undefined for the "/logout" route !!!
log.debug("cookies", JSON.stringify(req.cookies));
}
next();
});
app.use(passport.session());
app.use(app.router);
});
I have checked the browser and it sends the cookies to the server and in my "logger" middleware, i can see the fullURL is correctly set.
Also, the last query made to the redis db by the app, before failing, is a get "sess:xxx" on the correct session id (which is stored in the database correctly).
Why and what could be the reasons that, after after express.session() using connect-redis as a store submits to the next() middleware, the req.session is undefined, given the fact that the session is stored on the redis database and it DOES perform a "get" on it?
PS: While on the local server, with a local redis instance, everything works.
It looks like you're doing everything right, so I'm afraid I don't have a direct answer for you. However, I hope this will help you debug the problem.
The first thing I would do is look at the various failure conditions in the session middleware, and see if any of them might be an issue in your production environment. That code is located in your project directory here:
node_modules/express/node_modules/connect/middleware/session.js
Look for the line starting with function session(options){; that's where the party starts. About 25 lines later, you'll see return function session(req, res, next){; that's the actual middleware. If you browse through that source, you'll see various reasons why the session variable might not be set (anything that throws an error or returns next()). For example, the store can be disconnected, or there's a pathname mismatch. Sometimes, debug() is called on failure, so you could try enabling debugging logging. Just set the environment variable DEBUG to express:*. I haven't used Nodejitsu yet, but I'm sure there's a way you can set environment variables and examine your logs.
If you can enable remote debugging on Nodejitsu, then even better: that way you could actually step through the session middleware and find out where it's failing (or if it's not getting called for some reason). I looked through the public Nodejitsu documentation, and didn't see anything about remote debugging, but that doesn't mean it can't be done.

how can I check that a request is coming over https in express

I want force certain routes to always use a secure connection in my express app. How can I check to make sure it is using https?
I am using piggyback ssl on heroku for my deployments.
I deploy on Heroku as well. They add a bunch of their headers when they use nginx to reverse proxy. The one of interest in this case would be x-forwarded-proto.
This is what I did:
app.get(/\/register$/, function(req, res){
console.log(JSON.stringify(req.headers)); //to see all headers that heroku adds
if(req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === "http") {
res.redirect("https://" + req.headers.host + req.url);
}
else {
//the rest of your logic to handle this route
}
});
app.enable('trust proxy');
"Using Express behind a reverse proxy such as Varnish or Nginx is trivial, however it does require configuration. By enabling the "trust proxy" setting via app.enable('trust proxy'), Express will have knowledge that it's sitting behind a proxy and that the X-Forwarded-* header fields may be trusted, which otherwise may be easily spoofed."
Express behind proxies doco
In order to run a secure server (https) it would have to be created independently from a non-secure server (http). They would also listen on separate ports. Try something like this:
var express = require('express)
, app_insecure = express.createServer()
, app_secure = express.createServer({ key: 'mysecurekey' })
app_insecure.get('/secure-page',function(req, res){
// This is an insecure page, redirect to secure
res.redirect('https://www.mysecuresite.com/secure-page')
})
app_secure.get('/secure-page', function(req,res){
// Now we're on a secure page
})
app_insecure.listen(80)
app_secure.listen(443)
OR this could be implemented as route middleware
var redirect_secure = function(req, res, next){
res.redirect('https://mysite.com' + req.url)
}
app_insecure.get('/secure-page',redirect_secure,function(req, res){})
Now you would only have to include the function reference: redirect_secure() on the paths that you would like redirected to a secure location.

Resources