NodeJS HTTP代理服务器只能在SwitchOmega中工作

gmxoilav  于 2023-01-16  发布在  Node.js
关注(0)|答案(2)|浏览(210)

在提出这个问题之前,我做了大量的研究和实践。

说来话长:

我找到了一个关于如何用Node.js编写http代理的(非英语)教程。
到目前为止,我所知道和尝试的是:

  • HTTP代理可以处理HTTP请求和HTTPS请求,但处理方式不同。HTTP代理通过读取客户端的请求,向目标发出新的请求,并将响应返回给客户端来处理HTTP请求。对于HTTPS请求,则通过HTTPTunnel来处理。

  • Firefox代理设置中的SSL proxy字段和IE代理设置中的Secure字段(Windows)都是关于HTTP隧道的设置,如果设置了SSL proxySecure proxy,当浏览器要连接https站点时,它会发送CONNECT请求,而不是普通请求。

问题:

CONNECT请求是纯文本的,所以防火墙可以看到我想连接的主机并切断连接。所以我一开始就在想我是否可以使用https与代理服务器通信。我阅读了所有相关的帖子,但没有找到直接谈论这个问题的答案。有些答案还说"没有https代理服务器这样的东西"
但是教程说这是可以做到的(客户端和代理服务器之间的HTTPS,其他什么都不会改变)。所以我试了一下。我用我网站的证书把服务器改成了https。但是最终它只适用于Chrome中的Proxy SwitchOmega。在传统的设置中,比如Firefox代理或IE代理设置中,它不起作用。
代理交换机Omega设置:

Scheme|Protocol|Server|Port
....  | https  | .... |...

如果我启动https服务器,我必须在这里选择https协议。同样,如果我启动http服务器,我必须选择http协议。我也不知道这个protocol字段代表什么。
总结一下:

proxy server | Firefox proxy setting |work? | SwitchOmega setting |work?|
 http        | http + ssl setting    | yes  | protocol http       |yes  |
 https       | http + ssl setting    | no   | protocol https      |yes  |
 https       |      -                |  -   | protocal http       |no   |

所以我的问题是:
1.我可以通过普通的方式(没有扩展)连接到https代理服务器吗?如果可能,如何连接?
1.为什么可以通过SwitchOmega连接到https代理服务器?
1.我想我建立了一个https代理服务器,但是为什么其他人说"没有https代理服务器这样的东西?"

源代码

https服务器

var http = require('http');
var https = require('https');
var fs = require('fs');
var net = require('net');
var url = require('url');

console.log("qqqqq2");

function request(cReq, cRes) {
    console.log("request=====start");
    console.log(cReq.headers);
    console.log(cReq.url);
    console.log(cReq.method);
    console.log("request=====end");
    var u = url.parse(cReq.url);

    var options = {
        hostname : u.hostname, 
        port     : u.port || 80,
        path     : u.path,       
        method     : cReq.method,
        headers     : cReq.headers
    };

    var pReq = http.request(options, function(pRes) {
        cRes.writeHead(pRes.statusCode, pRes.headers);
        pRes.pipe(cRes);
    }).on('error', function(e) {
        cRes.end();
    });

    cReq.pipe(pReq);
    // console.log(cReq.headers);
    // console.log(cReq.method);
    // console.log(cReq.url);
    // console.log("^_^^_^^_^^_^^_^^_^");
    // cRes.writeHead('200');
    // cRes.end('hello world2222\n');
}

function connect(cReq, cSock) {
    console.log("connect=====start");
    console.log(cReq.headers);
    console.log(cReq.url);
    console.log(cReq.method);
    console.log("connect=====end");
    var u = url.parse('http://' + cReq.url);

    var pSock = net.connect(u.port, u.hostname, function() {
        cSock.write('HTTP/1.1 200 Connection Established\r\n\r\n');
        pSock.pipe(cSock);
    }).on('error', function(e) {
        cSock.end();
    });

    cSock.pipe(pSock);
}

var options = {
    key: fs.readFileSync('./privkey1.pem'),
    cert: fs.readFileSync('./fullchain1.pem')
};

https.createServer(options)
    .on('request', request)
    .on('connect', connect)
    .listen(9999, '0.0.0.0');

http服务器

var http = require('http');
var net = require('net');
var url = require('url');

console.log('qqqqq2');

function request(cReq, cRes) {
    console.log("request=====start");
    console.log(cReq.headers);
    console.log(cReq.url);
    console.log(cReq.method);
    console.log("request=====end");

    var u = url.parse(cReq.url);

    var options = {
        hostname : u.hostname, 
        port     : u.port || 80,
        path     : u.path,       
        method     : cReq.method,
        headers     : cReq.headers
    };

    var pReq = http.request(options, function(pRes) {
        cRes.writeHead(pRes.statusCode, pRes.headers);
        pRes.pipe(cRes);
    }).on('error', function(e) {
        cRes.end();
    });

    cReq.pipe(pReq);
}

function connect(cReq, cSock) {
    console.log("connect=====start");
    console.log(cReq.headers);
    console.log(cReq.url);
    console.log(cReq.method);
    console.log("connect=====end");
    var u = url.parse('http://' + cReq.url);

    var pSock = net.connect(u.port, u.hostname, function() {
        cSock.write('HTTP/1.1 200 Connection Established\r\n\r\n');
        pSock.pipe(cSock);
    }).on('error', function(e) {
        cSock.end();
    });

    cSock.pipe(pSock);
}

http.createServer()
    .on('request', request)
    .on('connect', connect)
    .listen(9999, '0.0.0.0');

测试服务器

你可以很容易地建立一个http代理服务器并测试它。但是建立一个https代理服务器可能会很麻烦,因为你需要部署证书。所以提供了一个https代理测试服务器,基于上面的代码。
测试服务器已删除,因为我找到了答案。

vx6bjr1n

vx6bjr1n1#

我在Security StackExchange中找到了答案。Is it possible to connect to a proxy with an ssl (or otherwise encrypted) connection?
来自www.example.com:https://wiki.squid-cache.org/Features/HTTPS#Encrypted_browser-Squid_connection :

加密的浏览器-Squid连接

    • 虽然HTTPS的设计工作主要集中在端到端通信上,但如果能够加密浏览器到代理的连接**(无需创建阻止Squid访问和缓存内容的CONNECT隧道),也会很好。例如,这将允许安全使用位于可能存在恶意网络的远程代理。

Squid可以使用https_port接受常规代理流量,就像Squid使用http_port指令一样。**不幸的是,流行的现代浏览器不允许配置TLS/SSL加密代理连接。**现在有针对大多数这些浏览器的公开错误报告,等待支持出现。如果您有任何兴趣,请帮助浏览器团队实现这一点。
...

chrome

如果在PAC文件或命令行开关中配置为使用SSL连接,Chrome浏览器可以通过SSL连接连接到代理。GUI配置似乎还不可能
火狐
Firefox 33.0浏览器能够通过TLS连接连接到代理,如果配置为使用PAC文件中的一个。GUI配置似乎还不可能,尽管有一个嵌入PAC逻辑的配置黑客。
有关Chrome的更多信息可以在http://dev.chromium.org/developers/design-documents/secure-web-proxy中找到。
要回答以下问题:
1.我可以通过普通的方式(没有扩展)连接到https代理服务器吗?如果可能,如何连接?
传统的设置http代理服务器的方式(例如Firefox中的Manual proxy configuration字段)仅适用于HTTP代理服务器。用户只能通过pac文件(例如Firefox中的Automatic proxy configuration URL字段)设置https代理。
1.为什么我可以通过SwitchOmega连接到https代理服务器?
SwitchOmega扩展实际上生成了一个pac文件供Chrome使用,尽管到目前为止我还不知道它如何与Chrome交互。
通过单击SwitchOmega中的Export PAC按钮,我得到一个包含以下内容的文件:

var FindProxyForURL = function(init, profiles) {
    return function(url, host) {
        "use strict";
        var result = init, scheme = url.substr(0, url.indexOf(":"));
        do {
            result = profiles[result];
            if (typeof result === "function") result = result(url, host, scheme);
        } while (typeof result !== "string" || result.charCodeAt(0) === 43);
        return result;
    };
}("+test", {
    "+test": function(url, host, scheme) {
        "use strict";
        if (/^127\.0\.0\.1$/.test(host) || /^::1$/.test(host) || /^localhost$/.test(host)) return "DIRECT";
        return "HTTPS myHttpsProxyServer.com:9999"; // This line matters
    }
});

https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file开始:

HTTP host:port   
The specified proxy should be used   
HTTPS host:port 
The specified HTTPS proxy should be used

1.我想我建立了一个https代理服务器,但是为什么其他人说"没有https代理服务器这样的东西?"
是的,我在tls连接上建立了一个https代理服务器/一个http代理服务器。那些说"没有https代理服务器这样的东西"的人是错误的。

deikduxw

deikduxw2#

AFAIK没有官方的HTTPS代理规范。
Rick在他的回答中提到的是Squid的黑客攻击,通过终止浏览器TLS请求,然后向目标服务器发起另一个TLS请求,允许他们缓存以前由于https而无法缓存的内容。本质上,Squid充当了浏览器和服务器之间的MITM。尽管连接仍然受到TLS保护,但Squid可以看到流量。如果Web服务器正在实施HSTS,浏览器不允许我们连接。
我期望从HTTPS代理是浏览器启动两个TLS连接。它首先启动TLS连接到代理服务器,然后请求连接到预期的Web服务器,并启动另一个TLS。

相关问题