Rob--W / cors-anywhere

CORS Anywhere is a NodeJS reverse proxy which adds CORS headers to the proxied request.
MIT License
8.68k stars 6.12k forks source link

Add way to blacklist / whitelist IP destination addresses #78

Open Rob--W opened 7 years ago

Rob--W commented 7 years ago

The default implementation of CORS Anywhere (server.js) does not restrict the target URLs. The ability to enforce restrictions based on the destination URLs has been requested in #67. Since I am going to add this to improve security, I should also do something with another glaring issue: Normally resources from servers on localhost or a local private network are not really open to the web. CORS Anywhere is designed to allow any website to read public data from any other website (credentials are explicitly stripped). However, information in a private network is likely not supposed to be public information, so such requests should be rejected by default.

Implementation plan

Public API

Support a new option, dnsLookup, with the following signature:

@param {string} hostname - The host name of the server to which CORS Anywhere
  should connect. If a proxy was configured via the `getProxyForUrl` method,
  then this will be the host name of that proxy (since the proxy is responsible
  for access control).
@param {function(err, address)} callback - The callback to be called when the
  address has been resolved. The request can be rejected by passing a suitable
  value of "err".

To get the current behavior (i.e. allow any IP), use the following implementation of dnsLookup:

var dns = require('dns');
require('cors-anywhere').createServer({
  // ...
  dnsLookup: function(hostname, callback) {
    // This is the default behavior of lookupAndConnect in Node.js "net" module.
    dns.lookup(hostname, { hints: dns.ADDRCONFIG }, callback);
  },
  // ...
}).listen(port, host); // <--- Assuming that host/port are set elsewhere.

Implementation details in CORS Anywhere

The implementation can look like this (replacing https://github.com/Rob--W/cors-anywhere/blob/143eff177c7e7d4bf241b83c57dd1e2c6378d53b/lib/cors-anywhere.js#L122-L123). (and also using location.href instead of location at https://github.com/Rob--W/cors-anywhere/blob/143eff177c7e7d4bf241b83c57dd1e2c6378d53b/lib/cors-anywhere.js#L87)

if (!req.corsAnywhereRequestState.dnsLookup) {
  // Start proxying the request
  proxy.web(req, res, proxyOptions);
  return;
}
var targetUrl = url.parse(proxyOptions.target);
req.corsAnywhereRequestState.dnsLookup(targetUrl.hostname, function(err, address) {
  if (err) {
    // TODO: Should errors just be propagated, or should we support something like
    // err.statusCode, err.statusText and err.message to customize the HTTP response?
    proxy.emit('error', err, req, res);
    return;
  }
  targetUrl.host = null; // Null .host so that .hostname + .port is used.
  targetUrl.hostname = address;
  proxyOptions.target = url.format(targetUrl);
  proxy.web(req, res, proxyOptions);
});
stevage commented 5 years ago

My use case for wanting this is to be able to deploy a staging version of a website outside the normal infrastructure. The backend services only support requests from the prod website. I therefore set up a CORS proxy, but I don't want it to be used for anything other than this one purpose.

fengshuo2004 commented 1 year ago

Any updates on this? I'd much appreciate the ability to block request to the server's local area network, perhaps have it as the default behaviour. Thank you!