Currently I make my node.js project create both http and https server.
var httpServer = http.createServer(app);
httpServer.listen(3000);
var httpsOptions = {
ca: fs.readFileSync(config.https.ssl.ca, 'utf8'),
key: fs.readFileSync(config.https.ssl.key, 'utf8'),
cert: fs.readFileSync(config.https.ssl.cert, 'utf8')
};
var httpsServer = https.createServer(httpsOptions, app);
httpsServer.listen(8000);
Also I used this middleware to redirect all http traffic to https.
app.all('*', function(req, res, next){
var host = req.header("host");
if (host && host.indexOf('localhost') !== -1) {
next()
} else if (req.connection.encrypted) {
next();
} else {
res.redirect('https://' + host + req.url);
}
});
But for some pages I do not need https connections, say http://www.domain.com/shops/ route. Can I make this route use http method and all other routes use https still?
p.s: this page request resources from other routes like bower_components, public, ... etc.
You can find request path as follows, which might help you to redirect your request accordingly.
var url_parts = url.parse(req.url);
console.log(url_parts);
console.log(url_parts.pathname);
Related
I have a small nodejs server which is working without a problem. Now I am trying to make use of "HTTPS" for security reasons. I have the following code, but when I try to open the page in Firefox via link [http://192.168.2.22:8080/api/users], on the terminal I see DIRECTING >>> https://192.168.2.22:8080/api/users but in the browser, instead of the expected response, I encounter this error:
Secure Connection Failed An error occurred during a connection to
192.168.2.22:8080. SSL received a record that exceeded the maximum permissible length.
Error code: SSL_ERROR_RX_RECORD_TOO_LONG
// Modules /////////////////////////////////////////////////////////////////////
const db = require('./db.js');
// Packages ////////////////////////////////////////////////////////////////////
const colors = require('colors');
const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
const fs = require('fs');
// Constant Variables //////////////////////////////////////////////////////////
const PORT_SERVER = 8080;
const HOST = '192.168.2.22';
////////////////////////////////////////////////////////////////////////////////
app.use(express.json({limit: '50mb'}));
// app.use(express.urlencoded({limit: '50mb'}));
// set up a route to redirect http to https
app.get('*', function(req, res) {
console.log('DIRECTING >>> https ://' + req.headers.host + req.url);
res.redirect('https://' + req.headers.host + req.url);
});
app.get('/api/users/', async (req, res) => {
console.log('CHECK POINT !!!');
let users = await db.db.get_users();
console.log("USERS : " + users);
res.send(users);
});
// have it listen on 8080
app.listen(PORT_SERVER, () => console.log(`Listen at ${PORT_SERVER}...`));
How can I resolve this? I could not find a solution that I can easily apply to my code, I am kind of a newbie for NodeJs.
Thanks in advance
You have not configured your server for SSL. Configure SSL using the https module like below. In this example, I have created two express one for Http and one for https as we can not run both http and non https on same port.
const express = require('express');
const http = require('http'),
const https = require('https')
const fs = require('fs')
const httpApp = express()
const app = express()
const httpsOptions = {
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt")
};
httpApp.set('port',80);
httpApp.get("*", function (req, res, next) {
res.redirect("https://" + req.headers.host + "/" + req.path);
});
app.set('port', 443);
app.enable('trust proxy');
http.createServer(httpApp).listen(httpApp.get('port'), function() {
console.log('Express HTTP server listening on port ' + httpApp.get('port'));
});
https.createServer(httpsOptions, app).listen(app.get('port'), function() {
console.log('Express HTTPS server listening on port ' + app.get('port'));
});
The Best way to redirect from non-http to https is to use Nginx web server as a reverse proxy and define redirection rule in Nginx config file.
client--->nginx reverse proxy(with SSL and redirection rules)-->express server
try changing the port to 443, https runs on 443 by default!
I'm trying to redirect http requests to https using nodejs.
Here is my code so far. I have included all key, certs etc.
http and https ports are ON ( custom ports, not defaults)
Now on hitting http, site does get redirected to https but it shows err as shown in screenshot attached. screenshot.
certs are valid ( see bottom of screenshot ) but still it says THIS PAGE IS NOT SECURE.
Please guide me where i'm wrong and possible solution.
I have searched here but couldn't get solution to this. Thanks.
var fs = require('fs');
var http = require('http');
var http_port =any_port;
var app = require('express')();
// HTTPS definitions
var https = require('https');
var https_port =another_port;
var options = {
key: fs.readFileSync('example.key'),
cert:fs.readFileSync('example.crt'),
ca: fs.readFileSync('bundleexample.crt')
};
app.get('/', function (req, res) {
res.end('Hello https World!');
});
https.createServer(options, app).listen(https_port, function () {
console.log('https port ' + https_port);
});
// Redirect from http port to https
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
res.end();
}).listen(http_port);
I'm just starting with node.js and express and I'm doing a simple HTTPS server. I've been working with nginx for some time and when I make an HTTP request to an HTTPS endpoint I get a "400 Bad Request" error. However, when using node.js the request never finishes.
How can I intercept an HTTP request in Express to be able to generate the "400 Bad Request" response?
This is my code:
var express = require('express');
var https = require('https');
var fs = require('fs');
var port = process.env.PORT || 8080;
var tls_options = {
key: fs.readFileSync('certs/server.key'),
cert: fs.readFileSync('certs/server.crt'),
ca: fs.readFileSync('certs/ca.crt'),
requestCert: true,
};
var app = express();
var router = express.Router();
router.get('/', function(req, res) {
res.json({ message: 'Checkpoint!!' });
});
app.use('/', router);
var secureServer = https.createServer(tls_options, app);
secureServer.listen(port);
console.log('Listening on port ' + port);
Until now the only thing I've been able to use is getting a 'connection' event every time a request arrives to the server:
secureServer.on('connection', function (stream) {
console.log('someone connected!');
});
Done. In fact, an HTTP request to an HTTPS socket ends after the default 120secs TLS handsahke timeout. This way I can end the request without waiting. I include the solution I used just for future references if anything needs the same functionality.
var secureServer = https.createServer(options, app);
secureServer.on('connection', function(socket) {
socket.on('data', function(data) {
var first_line = data.toString().split('\r\n')[0];
var pattern = /\bhttp\/1\.[01]$\b/i;
if (pattern.test(first_line)) {
var headers = {};
headers['Date'] = new Date().toUTCString();
headers['Connection'] = 'close';
var headers_string = '';
for (var name in headers) {
headers_string = headers_string + '\r\n' + name + ': ' + headers[name];
}
socket.end('HTTP/1.1 400 Bad Request' + headers_string);
}
});
There isn't a way of starting both HTTP and HTTPS servers on the same port. What most people do is either:
Start two servers (one HTTP and one HTTPS) on different ports, and redirect the HTTP traffic to HTTPS. Using Express it would mean the additional code:
// create two ports, one for HTTP and one for HTTPS
var port = process.env.PORT || 8080;
var httpsPort = 8081;
// redirect all HTTP requests to HTTPS
app.use(function(req, res, next) {
var hostname;
if (!req.secure) {
hostname = req.get("host").split(":")[0];
return res.redirect(["https://", hostname, ":", httpsPort, req.url].join(""));
}
next();
});
app.listen(port); // listen on HTTP
https.createServer(tls_options, app).listen(httpsPort); // listen on HTTPS
Or they use nginx or apache to handle outside connections (both HTTP and HTTPS) and redirect traffic to the Node server (which can then just run on HTTP).
I am trying to create a forward proxy capable of handling HTTPS websites as well. I am trying to observe and modify traffic for different sites. This is my code which works for http sites but not for https sites.
httpProxy.createServer(function(req, res, next) {
//custom logic
next();
}, function(req, res) {
var proxy = new httpProxy.RoutingProxy();
var buffer = httpProxy.buffer(req);
var urlObj = url.parse(req.url);
req.headers.host = urlObj.host;
req.url = urlObj.path;
console.log(urlObj.protocol);
setTimeout(function() {
proxy.proxyRequest(req, res, {
host: urlObj.host,
port: 80,
buffer: buffer,
}
)}, 5000);
}).listen(9000, function() {
console.log("Waiting for requests...");
});
Thanks for your help guys!
There are https options which must be specified when handling the https traffic. Here is what I am doing in my proxy setup.
var fs = require('fs'),
httpProxy = require('http-proxy');
var proxyTable = {};
proxyTable['domain.com'] = 'localhost:3001';
proxyTable['domain.com/path'] = 'localhost:3002';
proxyTable['sub.domain.com'] = 'localhost:3003';
var httpOptions = {
router: proxyTable
};
var httpsOptions = {
router: proxyTable,
https: {
passphrase: 'xxxxxxx',
key: fs.readFileSync('/path/to/key'),
ca: fs.readFileSync('/path/to/ca'),
cert: fs.readFileSync('/path/to/crt')}
};
httpProxy.createServer(httpOptions).listen(80);
httpProxy.createServer(httpsOptions).listen(443);
The documentation for https is on their github page as well.
https://github.com/nodejitsu/node-http-proxy
If you're just doing a forward proxy there's a few things you'll have to take into account.
A regular request is NOT triggered on a proxy for a HTTPS request - instead you'll see a HTTP CONNECT.
Here's the sequence flow you'll need to handle.
CONNECT event is sent from the browser to the proxy specified in the HTTPS section. You'll catch this here: http://nodejs.org/api/http.html#http_event_connect Note that this comes over the HTTP module, not the HTTPS connection.
You create a new socket connection to the requested domain (or your mapped domain). [srvSocket]
You'll respond back to the CONNECT socket with a 200
You'll write the buffer you received with the CONNECT event to srvSocket, then pipe the two sockets together srvSocket.pipe(socket);
socket.pipe(srvSocket);
Since you're trying to spoof the requested domain locally you'll need a few more things in place
You'll need to generate a root CA.
You will need to import this cert as a trusted authority to your OS
You'll use this cert to create a new key/cert file for the domains you're trying to access
Your mapped hosts will need to respond with the appropriate key/cert file generated in step 3 for EACH domain you are mapping.
https://github.com/substack/bouncy
var bouncy = require('bouncy');
var server = bouncy(function (req, res, bounce) {
if (req.headers.host === 'beep.example.com') {
bounce(8001);
}
else if (req.headers.host === 'boop.example.com') {
bounce(8002);
}
else {
res.statusCode = 404;
res.end('no such host');
}
});
server.listen(8000);
If you specify opts.key and opts.cert, the connection will be set to secure mode using tls. Do this if you want to make an https router.
We can have a middleware as below
request = require("request");
app.use(function (req, res, next) {
request('http://anotherurl.that.serves/the/request').pipe(res);
});
See example https://github.com/manuks/proxy
Basically, underneath the http-proxy npm is some networking libraries Node uses (specifically http://nodejs.org/api/https.html and TLS). Even though my Apache was able to connect me just fine on a self-signed certificate w/o the proxy by accessing it in my browser:
https://localhost:8002
You need to establish a certificate authority to get past the "unable to verify leaf signature" error in Node (I used the SSLCACertificateFile option). Then, you'll get hit with "self_signed_cert_in_chain". This led to some Google results indicating npm abandoned self-signed certificates, but I'm pretty sure this does not regard Node.
What you end up with are some people indicating you use process.env.NODE_TLS_REJECT_UNAUTHORIZED or rejectUnauthorized within your https agent. If you dig through the http-proxy souce, you'll find it accepts an agent option. Use this:
/**
* Module dependencies
*/
// basic includes
express = require('express');
fs = require('fs');
http = require('http');
https = require('https');
httpProxy = require('http-proxy');
require('child_process').spawn(__dirname+'/../../../dependencies/apache/bin/httpd.exe',['-f',__dirname+'/../../../dependencies/apache/conf/httpd-payments.conf']);
var app = module.exports = express();
app.set('port', process.env.PORT || 8001); // we sometimes change the port
// creates an output object for this particular request
//app.use(express.cookieParser(''));
//app.use(express.bodyParser());
//app.use(express.methodOverride());
proxy = httpProxy.createProxyServer();
proxy.on('error', function (err, req, res) {
console.log(err);
res.send(500,err);
res.end();
});
app.all('*',function(req,res,next) {
var options = {
hostname: '127.0.0.1',
port: 8002,
rejectUnauthorized: false,
key: fs.readFileSync(__dirname+"/../../../deployment/server.key.pem"),
cert: fs.readFileSync(__dirname+"/../../../deployment/server.crt.pem")
};
agent = new https.Agent(options);
try {
proxy.web(req,res, {
target: "https://localhost:8002",
proxyTimeout: 30,
agent: agent
});
} catch(e) {
// 500 error
res.send(500,e);
}
})
/**
* Start Server
*/
var options = {
key: fs.readFileSync(__dirname+"/../../../deployment/server.key.pem"),
cert: fs.readFileSync(__dirname+"/../../../deployment/server.crt.pem")
};
server = https.createServer(options,app).listen(app.get('port'), function () {
console.log('Running payments server on port ' + app.get('port'));
});
I am trying to redirect my http page to https, I found some discussion already there in stackoverflow How to force SSL / https in Express.js.
But now http = express.createServer() has become deprecated.
So I was trying to do as below:
var http = require("http")
, https = require("https");
var app = express();
/* If I use below it gives ECONNREFUSED error */
http.get('*', function(req, res) {
var path = req.headers.host;
var pos = path.indexOf(':');
res.redirect('https://' + path.substr(0, pos) + ':' + String(app.get('port')));
});
app.get('/', function(req, res) {
//Something
});
https.createServer(options, app).listen(8000, function(){
console.log("In Https");
});
http.createServer(app).listen(9000, function() {
console.log("In http");
});
Can you please let me know why this error comes here? (ECONNREFUSED)
What I should modify to get it worked, http redirect to https?
Regards,
-M-