Add extra headers on Express NodeJS server - node.js

I am trying to put some extra headers on the responses sent by a https server created with Express. For example, I want to set a X-Frame-Options response header.
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('../certificate/ca.key'),
cert: fs.readFileSync('../certificate/ca.crt')
};
module.exports = https.createServer(options, app).listen(port, function (err) {
if (err)
return console.log(err);
var uri = 'https://localhost:' + port;
opn(uri);
});
I tried various things, but none of them worked. Did anybody manage to do such thing?

I managed to use Helmet in order to set the headers I needed.

Related

node.js Socket.io cors from null

I created a server over ssl with Node.js and I will use socket.io.
When I type https://socket.com/test on the browser via my code below, it works. There is no problem.
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
var io = require('socket.io')(https);
// This line is from the Node.js HTTPS documentation.
var options = {
key: fs.readFileSync('/etc/ssl/ssl-keys/crunchsystem/key.pem'),
cert: fs.readFileSync('/etc/ssl/ssl-keys/crunchsystem/cert.pem')
};
var app = express();
// Create a service (the app object is just a callback).
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get('/test',function(request, response) {
response.send(JSON.stringify({ status:'ok' }));
});
app.post('/order', function(request, response) {
if (request.body.restaurant_code !== undefined) {
io.of('/'+request.body.restaurant_code).emit('GetOrder', request.body.data);
}
response.send(JSON.stringify({ status: request.body.restaurant_code }));
});
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
However ... When I try to listen to the channel, it keeps giving a cors error.
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script>
var socket = io.connect('https://socket.crunchsystems.com/foo');
console.log(socket);
socket.on('GetOrder', msg => {
console.log(msg)
})
</script>
from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
There's always this error.How do I solve this error? Can you help me?
I've tried all kinds of solutions, I've tried everything that happens on the Internet.

What are the minimum requirements to get a secure WebSocket working with Node.js?

When it comes to WebSockets, it seems the internet has plenty of ws:// (insecure) tutorials, but hardly any on wss:// (secure). I've got an insecure websocket connection working fine with Node.js thanks to Supun Kavinda's tutorial, but can't get it to work as a secure connection.
Here's the summarized working code for the insecure connection (fake ip address):
File: js-index.js
window.WebSocket = window.WebSocket || window.MozWebSocket;
var connection = new WebSocket('ws://3.00.00.00:8080');
File: server.js
const https = require('https');
const fs = require('fs');
var WebsocketServer = require('websocket').server;
var server = https.createServer(function(request,response) {
function getPostParams(request, callback) {
var qs = require('querystring');
if (request.method == 'POST') {
var body = '';
request.on('data', function (data) {
body += data;
// Too much POST data, kill the connection!
if (body.length > 1e6)
request.connection.destroy();
});
request.on('end', function () {
var POST = qs.parse(body);
callback(POST);
});
}
}
if (request.method === "POST") {
getPostParams(request, function(POST) {
messageClients(POST.data);
response.writeHead(200);
response.end();
});
return;
}
});
server.listen(8080);
/*Handling websocket requests*/
var websocketServer = new WebsocketServer({
httpServer: server
});
websocketServer.on("request", websocketRequest);
global.clients = {}; // connected clients
var connectionId = 0;
function websocketRequest(request) {
var connection = request.accept(null, request.origin);
connectionId++;
clients[connectionId] = connection;
}
function messageClients(message) {
for (var i in clients) {
clients[i].sendUTF(message);
}
}
For a secure connection, I have tried many things, mainly centered on changing ws:// to wss://, and including a .pem certificate/key in the createServer() call, like so:
const ssl_creds = {
cert: fs.readFileSync('/opt/bitnami/apache2/htdocs/fullchain.pem'),
key: fs.readFileSync('/opt/bitnami/apache2/htdocs/privkey.pem')
};
var server = https.createServer(ssl_creds, function(request,response) {....
However, I continue to get errors (only testing in Chrome thus far), such as:
Error in connection establishment: net::ERR_CERT_COMMON_NAME_INVALID
Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
^#1 being the problem I encounter most
I'm using the same ssl credentials granted by LetsEncrypt for my website itself - I assume that is okay?
In summary, most of the tutorials I've found either do something exactly like this, or talk about how something like NGINX is required to setup proxies/tunnels - something I am completely clueless on.
Can someone tell me if proxy configurations are typically required for this, or if I'm just missing something small/dumb? Any insight at all would be appreciated. In case it's relevant, I'm just cutting my teeth on AWS with a Lightsail PHP image from Bitnami.

node js ssl certificates issue

When I run the code like below on Node.JS v0.10.36 - server responds on https request, but then I run the same code on Node.JS v4.2.1 - server doesn't respond at all,however in that time browser does not "say" that anything goes wrong - it just continues to load the page. Should I rewrite the code in some way?
var express = require('express');
var https = require('https');
//var http = require('http');
var fs = require('fs');
var crypto=require('crypto')
var app = express();
var ssl_conf=require(__dirname+'/config/ssl.json');
var secureContext = {}
try{
for(var domain in ssl_conf){
secureContext[domain]=getSecureContext(ssl_conf[domain].domain);
}
}
catch(err){
console.log('error with ssl.config file '+err);
}
function getSecureContext (domain) {//returns secure context
return crypto.createCredentials({
key: fs.readFileSync('./ssl/'+domain+'.key'),
cert: fs.readFileSync('./ssl/'+domain+'.crt')
}).context;
}
var options = {
SNICallback: function (domain) {
return secureContext[domain];
},
//in case SNI is not available use this cert
cert: fs.readFileSync('./ssl/2_helena.softpro.ua.crt'),
key: fs.readFileSync('./ssl/2_helena.softpro.ua.key')
}
app.get('/',function(req,res){//simple route
res.send("your domain is "+req.hostname);
})
https.createServer(options, app).listen(443,function(){//run server
console.log('https server running on 443')
});
In recent version 12.0.0 + next code is ok
var options = {
SNICallback:function(domain,cb){
var ctx= tls.createSecureContext(
secureContext[domain]//{key:<Buffer>,cert:<Buffer>}
).context
if(cb)
cb(null,ctx)
else
return ctx;
}
}

expressjs 4.x and https, generate key and certificate

I want to create an https server with express 4.x. Even if a lot of code found on google is based on express 3.x I think I made the port correctly.
Even if I tried to goole it is not very clear to me how to generate the keys. Without the key I'm expecting 401.
I tried with the script found in this gist. But I'm keeping on receiving the error Error: DEPTH_ZERO_SELF_SIGNED_CERT.
I'd like to test it both with curl, request, and super test.
This is what actually I have:
server.js
var express = require('express')
, https = require('https')
, fs = require('fs');
var privateKey = fs.readFileSync('./server/server-private-key.pem').toString();
var certificate = fs.readFileSync('./server/server-certificate.pem').toString();
var options = {
key : privateKey
, cert : certificate
}
var app = express();
app.get('/', function(req, res) {
req.client.authorized ?
res.json({"status":"approved"}) :
res.json({"status":"denied"}, 401);
});
server = https.createServer(options,app);
var port = 12345;
server.listen(port, function(){
console.log("Express server listening on port " + port);
});
client.js
var https = require('https');
var fs = require('fs');
var options = {
host: 'localhost',
port: 12345,
method: 'GET',
path: '/',
key: fs.readFileSync('./client/client-private-key.pem'),
cert: fs.readFileSync('./client/client-certificate.pem'),
headers: {}
};
var req = https.request(options, function(res) {
console.log('dudee');
console.log(res);
});
req.end();
With cURL you can use the -k flag to bypass the self-signed cert problem.
With request you can just set rejectUnauthorized: false in the request options.

creating a forward https proxy using http-node-proxy

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'));
});

Resources