【问题标题】:creating a forward https proxy using http-node-proxy使用 http-node-proxy 创建转发 https 代理
【发布时间】:2013-05-30 11:05:56
【问题描述】:

我正在尝试创建一个能够处理 HTTPS 网站的转发代理。我正在尝试观察和修改不同站点的流量。这是我的代码,适用于 http 网站,但不适用于 https 网站。

httpProxy.createServer(function(req, res, next) {
   //custom logic
   next();
}, function(req, res) {
   var proxy = new httpProxy.RoutingProxy();
   var buffer = httpProxy.buffer(req);
   var urlObj = url.parse(req.url);
   req.headers.host = urlObj.host;
   req.url = urlObj.path;
   console.log(urlObj.protocol);
  setTimeout(function() {
     proxy.proxyRequest(req, res, {
        host: urlObj.host,
        port: 80,
        buffer: buffer,
    }
   )}, 5000);

}).listen(9000, function() {
console.log("Waiting for requests...");
});

感谢你们的帮助!

【问题讨论】:

    标签: node.js http-proxy node-http-proxy


    【解决方案1】:

    基本上,http-proxy npm 下面是 Node 使用的一些网络库(特别是 http://nodejs.org/api/https.html 和 TLS)。即使我的 Apache 能够通过在我的浏览器中访问它而在没有代理的自签名证书上很好地连接我:

    https://localhost:8002    
    

    您需要建立一个证书颁发机构才能通过 Node 中的“无法验证叶签名”错误(我使用了 SSLCACertificateFile 选项)。然后,你会被“self_signed_cert_in_chain”击中。这导致一些谷歌结果表明 npm 放弃了自签名证书,但我很确定这与 Node 无关。

    你最终得到的是一些人表明你在你的 https 代理中使用 process.env.NODE_TLS_REJECT_UNAUTHORIZEDrejectUnauthorized。如果您深入研究 http-proxy 源,您会发现它接受代理选项。使用这个:

    /**
     * Module dependencies
     */
    
    // basic includes
    express     = require('express');
    fs          = require('fs');
    http        = require('http');
    https       = require('https');
    httpProxy   = require('http-proxy');
    require('child_process').spawn(__dirname+'/../../../dependencies/apache/bin/httpd.exe',['-f',__dirname+'/../../../dependencies/apache/conf/httpd-payments.conf']); 
    
    var app     = module.exports = express();
    app.set('port', process.env.PORT || 8001); // we sometimes change the port
    
    // creates an output object for this particular request
    //app.use(express.cookieParser(''));
    //app.use(express.bodyParser());
    //app.use(express.methodOverride());
    
    proxy   = httpProxy.createProxyServer();
    proxy.on('error', function (err, req, res) {
        console.log(err);
        res.send(500,err);
        res.end();
    });
    
    app.all('*',function(req,res,next) {
        var options = {
          hostname: '127.0.0.1',
          port: 8002,
          rejectUnauthorized: false,
          key: fs.readFileSync(__dirname+"/../../../deployment/server.key.pem"),
          cert: fs.readFileSync(__dirname+"/../../../deployment/server.crt.pem")
        };
        agent = new https.Agent(options);
        try {
            proxy.web(req,res, {
                target: "https://localhost:8002",
                proxyTimeout: 30,
                agent: agent
            });
        } catch(e) {
            // 500 error
            res.send(500,e);
        }
    })
    
    /** 
     * Start Server
     */
    
    var options = {
      key: fs.readFileSync(__dirname+"/../../../deployment/server.key.pem"),
      cert: fs.readFileSync(__dirname+"/../../../deployment/server.crt.pem")
    };
    server  = https.createServer(options,app).listen(app.get('port'), function () {
      console.log('Running payments server on port ' + app.get('port'));
    });
    

    【讨论】:

      【解决方案2】:

      我们可以有如下中间件

      request = require("request"); app.use(function (req, res, next) { request('@987654321@').pipe(res); });

      参见示例https://github.com/manuks/proxy

      【讨论】:

        【解决方案3】:

        如果您只是在做一个转发代理,那么您必须考虑一些事情。

        • HTTPS 请求的代理不会触发常规请求 - 相反,您会看到 HTTP CONNECT。

        这是您需要处理的序列流。

        1. CONNECT 事件从浏览器发送到 HTTPS 部分中指定的代理。你会在这里看到这个:http://nodejs.org/api/http.html#http_event_connect 请注意,这来自 HTTP 模块,而不是 HTTPS 连接。
        2. 您创建了一个到请求域(或您的映射域)的新套接字连接。 [srvSocket]
        3. 您将使用 200 响应 CONNECT 套接字
        4. 您将通过 CONNECT 事件接收到的缓冲区写入 srvSocket,然后将两个套接字连接在一起srvSocket.pipe(socket);
        5. socket.pipe(srvSocket);

        由于您试图在本地欺骗所请求的域,因此您需要做更多的事情

        1. 您需要生成根 CA。
        2. 您需要将此证书作为受信任的权威机构导入您的操作系统
        3. 您将使用此证书为您尝试访问的域创建新的密钥/证书文件
        4. 您的映射主机需要使用在第 3 步中为您要映射的每个域生成的相应密钥/证书文件进行响应。

        【讨论】:

          【解决方案4】:

          https://github.com/substack/bouncy

          var bouncy = require('bouncy');
          
          var server = bouncy(function (req, res, bounce) {
              if (req.headers.host === 'beep.example.com') {
              bounce(8001);
              }
              else if (req.headers.host === 'boop.example.com') {
                  bounce(8002);
              }
              else {
                  res.statusCode = 404;
                  res.end('no such host');
              }
          });
          server.listen(8000);
          

          如果您指定 opts.key 和 opts.cert,则连接将使用 tls 设置为安全模式。如果您想制作 https 路由器,请执行此操作。

          【讨论】:

            【解决方案5】:

            在处理 https 流量时必须指定一些 https 选项。这是我在代理设置中所做的。

            var fs = require('fs'),
                httpProxy = require('http-proxy');
            
            var proxyTable = {};
            
            proxyTable['domain.com'] = 'localhost:3001';
            proxyTable['domain.com/path'] = 'localhost:3002';
            proxyTable['sub.domain.com'] = 'localhost:3003';
            
            var httpOptions = {
                router: proxyTable
            };
            
            var httpsOptions = {
                router: proxyTable,
                https: {
                    passphrase: 'xxxxxxx',
                    key: fs.readFileSync('/path/to/key'),
                    ca: fs.readFileSync('/path/to/ca'),
                    cert: fs.readFileSync('/path/to/crt')}
            };
            
            httpProxy.createServer(httpOptions).listen(80);
            httpProxy.createServer(httpsOptions).listen(443);
            

            https 的文档也在他们的 github 页面上。

            https://github.com/nodejitsu/node-http-proxy

            【讨论】:

            • 所以我在本地主机上运行代理并且还需要代理 https 站点。这是否意味着我需要为本地主机创建一个自签名证书?
            • 您需要为您代理的任何 SSL 站点提供证书。在我的示例中,我有一个 domain.com 的通配符,并且所有代理项都可以作为 http 和 https 使用。
            • 说我要代理Facebook的response,修改response然后发送给用户,是不是需要有Facebook的证书?我想对用户可能浏览到的所有 https 站点执行此操作..
            • 澄清一下,我在本地主机上运行节点代理,并通过系统设置手动将代理设置为本地主机和我的端口,将所有请求和响应代理到本地服务器。跨度>
            • 只是为了清楚您的方案...您正在设置本地代理,并修改主机文件,以便互联网请求通过您的本地连接并返回到预期目标?在这种情况下,是的,您需要为 Facebook.com 签名的证书。自签名证书会加密流量,但 Facebook 无法解密后续请求。浏览器还会抛出关于证书的警告/错误页面。所有这些事情都是为了防止你试图做的事情相当于中间人的攻击。
            猜你喜欢
            • 1970-01-01
            • 2013-09-14
            • 1970-01-01
            • 2020-02-06
            • 2013-04-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-25
            相关资源
            最近更新 更多