Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to block post request from different origin in node

I'm going through this tutorial for building a node api:

http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4

They go through how to test post requests with getpostman.com.

However - I don't want my application to respond to post requests from different domains. I only want it to respond to post requests from Rails on my domain (not browser). How do I stop accepting these requests from foreign origins, yet allow the requests from my rails server?

I tried middleware like the below which I found from this link. But didn't work. This has to be easy. Any clues?

router.all('/', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "https://www.example.com");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.header("Access-Control-Allow-Methods", "POST GET");
  res.header("X-Frame-Options", "ALLOWALL");
  res.header("Access-Control-Allow-Credentials", "true");
  next();
 });
like image 548
bumpkin Avatar asked Mar 19 '23 08:03

bumpkin


1 Answers

You can check where a request came from by checking the client's IP as described here. You can then compare it to a list of allowed addresses or do a reverse DNS lookup to check against a domain. The latter approach should be implemented carefully and it might be better to first resolve the allowed domains and check against a set of static IP addresses.

Here is a small module which exports a middleware which will do exactly that (not even tested once).

// allowed is an array of allowed hosts
// readyCb is an optional function that will be called
// once all host names have been resolved
module.exports = function(allowed, readyCb) {
  // Resolve all domains
  var ips = [];
  var remaining = allowed.length;
  allowed.forEach(function(host) {
    if(/^[.0-9]+$/.test(host)) {
      // Should be an IP address
      ips.push(host);
      remaining--;
      if(!remaining && readyCb) readyCb();
    } else {
      // Resolve the host name
      // Adapt this if you want IPv6 support
      require('dns').resolve(host, 'A', function(err, addresses) {
        remaining--;
        if(!err) {
          addresses.forEach(function(ip) { ips.push(ip); });
        } else {
          // Handle the error, either using an additional callback
          // or by collecting all errors and submitting them to
          // readyCb
        }
        if(!remaining && readyCb) readyCb();
      });
    }
  });
  return function(req, res, next) {
    var clientIp = req.ip;
    // Check if the address is allowed
    if(ips.indexOf(clientIp) == -1) {
      res.end(403, 'Remote host is not allowed to use the API');
    } else {
      next();
    }
  };
};

Original answer for browser requests

Use a middleware like this:

var url = require('url'); // standard node module

function(req, res, next) {
  var ref = req.headers.referer;
  if(ref) {
    // We got a referer
    var u = url.parse(ref);
    if(u && u.hostname === 'myhost.com') {
      // Correct host, process the request
      return next();
    }
  }
  // Send some kind of error
  res.send(403, 'Invalid origin');
}

Please note that the referer header might be unavailable. Adapt the above snippet to react to such situations.

like image 144
Tobias Avatar answered Mar 23 '23 08:03

Tobias