How To Use Express Middleware To Filter Traffic In Node.js

How To Use Express Middleware To Filter Traffic In Node.js

With the introduction of Node.js in TIBCO Cloud Integration you have an amazing toolset to connect to almost anything and build APIs. In fact, there is a good chance that if you know Node.js that your first application was a simple application that said “Hello World” every time (your first API!). Let’s create a custom Express middleware that checks if the IP address of the sender matches a predefined list. In this tutorial we’ll use the list of TIBCO Mashery Traffic Managers as a ‘whitelist’ (so traffic from all other IP addresses will be blocked).

Some assumptions

There are a few assumptions that I’ve made while writing this tutorial, which should cover the majority of the people reading it. If you have any questions, feel free to post them below or at the TIBCO Community!

Express middleware

Middleware are functions in Node.js that have access to the request and response objects in your Express app. From the website of Express you can find that middleware is very useful for to perform certain tasks, like:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware in the stack.

In this case we’re very interested in the third and fourth bullet. If the request doesn’t come from Mashery we need to end the cycle and if it does come from Mashery we can call the next middleware in the stack.

Let’s write some code

In essence we need our new middleware to do one very simple thing, check whether the IP address the request comes from is a Mashery Traffic Manager IP address. The code we create should fulfill three requirements:

  • As we want to test locally and run the same code in TIBCO Cloud Integration we need to check two parameters. We need to check the x-forwarded-for and we need to check the remoteAddress.
  • The list of IP addresses published by Mashery are in CIDR format so we also need to translate those into ‘normal’ IP addresses to see whether or not the IP addresses match.
  • We want to be compliant with the Node.js best practices so we’ll put this new middleware into a new file. In my case I’ve called it mashery.js and stored it in the ‘util’ folder.
'use strict';

var ip = require('ip');
var Logger = require('./logger');

/**
* To test locally add '::1/32' or '127.0.0.1/32' to the list.
*/
var trafficManagerIPs = ['64.94.14.0/27',
   '64.94.228.128/28',
   '216.52.39.0/24',
   '216.52.244.96/27',
   '216.133.249.0/24',
   '23.23.79.128/25',
   '107.22.159.192/28',
   '54.82.131.0/25',
   '75.101.137.168/32',
   '75.101.142.168/32',
   '75.101.146.168/32',
   '75.101.141.43/32',
   '75.101.129.141/32',
   '174.129.251.74/32',
   '174.129.251.80/32',
   '50.18.151.192/28',
   '50.112.119.192/28',
   '54.193.255.0/25',
   '204.236.130.149/32',
   '204.236.130.201/32',
   '204.236.130.207/32',
   '176.34.239.192/28',
   '54.247.111.192/26',
   '54.93.255.128/27',
   '54.252.79.192/27'];

module.exports = function (req, res, next) {
   var invalidMasheryIP = true;
   var reqIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

   for (var i = 0, len = trafficManagerIPs.length; i < len; i++) {
       if (ip.cidrSubnet(trafficManagerIPs[i]).contains(reqIp)) {
           invalidMasheryIP = false;
           next();
       }
   }

   if (invalidMasheryIP) {
       Logger.log(Logger.LOG_WARN, `An unauthorized IP address ${reqIp} has tried to access the service`);
       res.status(403).end();
   }
};

Use it in your Node.js app

We want to make sure that our Node.js app first checks if the request was forwarded by Mashery or not. To do that you need to ‘require’ the new file and add a new App.use line above all others. For my Node.js app it looks like below:

'use strict';

var Http = require('http');
var mashery = require('./util/mashery');

...

App.use(mashery);

...

Conclusion

With a few lines of code (and a bit of copy/paste) you can very easily confirm whether or not the request was sent from a particular IP. The only thing left is to deploy your Node.js app.

Let's connect

If you have any questions or comments, feel free to drop me a note on Twitter!