如何在节点中阻止来自不同来源的发布请求

Posted

技术标签:

【中文标题】如何在节点中阻止来自不同来源的发布请求【英文标题】:how to block post request from different origin in node 【发布时间】:2014-08-04 18:34:54 【问题描述】:

我正在阅读本教程以构建节点 api:

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

他们了解如何使用 getpostman.com 测试发布请求。

但是 - 我不希望我的应用程序响应来自不同域的发布请求。我只希望它响应来自我域(而不是浏览器)上 Rails 的发布请求。如何停止接受这些来自国外的请求,但允许来自我的 rails 服务器的请求?

我尝试了从this 链接中找到的如下中间件。但是没有用。这必须很容易。有什么线索吗?

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();
 );

【问题讨论】:

【参考方案1】:

您可以通过检查客户端的 IP 为 described here 来检查请求的来源。然后,您可以将其与允许的地址列表进行比较,或者进行反向 DNS 查找以检查域。后一种方法应谨慎实施,最好先解析允许的域并检查一组静态 IP 地址。

这是一个导出中间件的小模块,它可以做到这一点(甚至没有测试过一次)。

// 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();
    
  ;
;

浏览器请求的原始答案

使用这样的中间件:

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

请注意,引用标头可能不可用。调整上述 sn-p 以应对此类情况。

【讨论】:

每当我尝试来自 getpostman.com 或我的 rails 服务器的发布请求时,u.hostname 为空。另外,有人可以伪造主机名吗? 澄清 - 我们将从 Rails 发送发布请求,而不是直接从浏览器发送(更新问题)。

以上是关于如何在节点中阻止来自不同来源的发布请求的主要内容,如果未能解决你的问题,请参考以下文章

来自多个来源的 CORS

来自除 localhost 之外的每个来源的 CORS 策略阻止的对外部 API 的 HTTP 请求

来自来源的 XMLHttpRequest 已被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头

AWS - 防火墙管理器 - WAF 规则如何阻止来自 IP 地址的请求(无主机名)?

如何修复“评估已被 CORS 政策阻止:反应中没有“访问控制允许来源”

如何阻止相同的广播(来自 PendingIntent)排队?