Node the Super Hero

Node is really starting to become my go to language these days. The first couple of servlets I've created just help me monitor code changes and web server availability. But this week we were handed a most difficult problem which had a large monetary impact on a point of sale system (POS). A non-profit who is in the middle of moving their contact and membership management software to a new vendor found out there is a major security change happening to their current POS. The current POS is not TLS 1.2 compatible because their original vendor is a bunch of idiots and hard coded the TLS protocol into their system.

Since this is only going to be a temporary solution that will run for a couple of month we decided to look into how Node could help them extend the life of their old POS and make a secure connections to their credit card processor (CCP). It turns out in a couple of days this CCP is going to turn off support for TLS 1.1 only allowing TLS 1.2 connections. We tried to test only allowing the server to use TLS 1.2 which the server can but this shut down their connection to the database server which only uses TLS 1.0. There is a patch that will make this work but unfortunately the software vendor still wouldn't work because of hard coded connections.

Being a network engineer and a programmer we thought using a proxy concept might fix this problem. The idea is the proxy server would just take in the request from the POS to the CCP. So instead of letting the POS go directly to the CCP we inserted a server that would accept connections from the POS and then forward them on in the more secure TLS 1.2 protocol. Now for those security elites out there remember this is only a temporary solution until their new POS system get put in place which uses the highest PCI compliance and is certified. Oh and don’t forget these two servers are on a dedicated private network protected by a next gen firewall. Still not the most secure but a lot better than sending TLS 1.0 request across the internet.

For node to do this we needed to use several really good projects to build a simple proxy service. The first critical one is the https build in node. It allows us to load up a SSL certificate between the POS and the proxy server. Once we started listening in on port 443 we could accept secure requests. Now all we have to do is read the data from the request, reform a new request, send if forward to the CCP, wait for a response, and finally send the response back to the server. Believe it or not this is a lot of waiting for the server. 30 seconds is a very long time to a server.

So with HTTPS working the next problem was find the post data. This took some time and the key was to check the kind request was received on the HTTPS server. If it is a POST then we need to do an async call to the data event and just add the data to a variable. This may be called a couple of times so we just append it to the variable until the end is reached. The last event we want to listen for is “end” and then we can send the request on to the CCP. The code looks like this:

let theData = url.parse(req.url, true).query;
if (req.method === 'POST') {
	let data = '';
	req.on('data', function (d) {
		data += d;
	}).on('end', function () {
		me.processResponse(req, res, data);
	});
} else {
	me.processResponse(req, res, theData);
}

This simple bit of code first pulls the variables off the request URL and makes them a simple JavaScript object. Next it check for the type of request we are handling which can either be POST or GET. If it is a POST then we need to connect to the data event and store it for the processResponse function. The other thing to note is since this is purely a node script we decided to use the let declaration of our variables. If this code was going to be processed by a browser at some point we would have used the old var declaration instead for the most compatibility.

So to perform the next step we used the request library to build a new post call to the CCP. This is the next section of code used to finally process the request with the CCP:

request.post({
	headers: { 'content-type': 'application/x-www-form-urlencoded'},
	url: me.dest.hostname,
	body: theData,
	timeout: me.dest.timeout
}, function (e, myres, body) {
	res.statusCode = myres.statusCode;
	res.setHeader('content-type', myres.headers['content-type']);
	res.end(body);
	me.log('Response: ' + myres.statusCode);
});

The most important part here is setting the timeout for the post request. When we didn’t set this the server kept return a blank result and failing. For our CCP we had to set the timeout to 30 seconds but check your CCP specifications. Our theData variable just contains the initial request so this is where we are just binding this to the new request. Now once the request is done we will get the results of the request in the body. For this we will just pass it back to the original request and be done.

That is all there is to how a simple proxy server works in Node. This code will be put into production for a couple of months in order to help our customer out during their transition between POS system.

A note about this code and concept. For security reasons we don’t recommend using this as a permanent solution. Also this code is not battle tested meaning it has never been in production and dealt with the constraints of a production environment. When working with connections like this it is important that the code can recover gracefully from just about any kind of problem.