简体   繁体   English

HTTPS代理实现(SSLStream)

[英]HTTPS Proxy Implementation (SSLStream)

I've written a console application that acts as a proxy server. 我编写了一个充当代理服务器的控制台应用程序。 Now I like to implement SSL as well. 现在我也想实现SSL。 Do not like to decrypt any traffic. 不喜欢解密任何流量。 Just like a normal https proxy. 就像普通的https代理一样。 I'm not sure how I should go on. 我不确定我该怎么做。

var host = text.Remove(0, connectText.Length + 1);
var hostIndex = host.IndexOf(" ", StringComparison.Ordinal);
var hostEntry = host.Remove(hostIndex).Split(new []{":"}, StringSplitOptions.None);
requestClient.Connect(hostEntry[0], Convert.ToInt32(hostEntry[1]));
requestStream = requestClient.GetStream();
var sslStream = new SslStream(requestStream, false, (x1,x2,x3,x4) => true);
sslStream.AuthenticateAsClient(hostEntry[0]);
const string sslResponse = "HTTP/1.0 200 Connection established\r\n\r\n";
var sslResponseBytes = Encoding.UTF8.GetBytes(sslResponse);
proxyStream.Write(sslResponseBytes, 0, sslResponseBytes.Length);
proxyStream.Flush();

Should I directly write everything into sslStream? 我应该直接将所有内容写入sslStream吗? What about the browser connection proxyClient . 浏览器连接proxyClient怎么样? Did I need to wrap the stream as well or can I just write everything directly into proxyStream ? 我是否也需要包装流,或者我可以直接将所有内容写入proxyStream Should I use AuthenticateAsServer and pass somehow the certificate from AuthenticateAsClient? 我应该使用AuthenticateAsServer并以某种方式从AuthenticateAsClient传递证书吗?

  1. IE issues a CONNECT request to my proxy IE向我的代理发出CONNECT请求
  2. my proxy sees that it's a CONNECT request and gets the IP: port of the destination (eg, www.hotmail.com:443) 我的代理看到它是一个CONNECT请求并获取目标的IP:端口(例如,www.hotmail.com:443)
  3. my proxy creates a new TCP connection to www.hotmail.com:443 我的代理创建了一个到www.hotmail.com:443的新TCP连接
  4. my proxy gets a SslStream from this destination and calls AuthenticateAsClient - this gives my proxy a secure connection to the Hotmail side of things 我的代理从这个目的地获取一个SslStream并调用AuthenticateAsClient - 这为我的代理提供了一个与Hotmail方面的安全连接
  5. my proxy then sends an "HTTP/1.0 200" message back to the browser to say that the CONNECT was successful 我的代理然后将“HTTP / 1.0 200”消息发送回浏览器,表示CONNECT成功
  6. my proxy then gets a SslStream from the browser connection and calls AuthenticateAsServer - gives my proxy a secure connection to the browser side of things 我的代理然后从浏览器连接获取SslStream并调用AuthenticateAsServer - 为我的代理提供与浏览器端的安全连接

I saw this, but how AuthenticateAsServer without a fake certificate. 我看到了这个,但AuthenticateAsServer如何没有假证书。 Can I just write that like in my normal streams or should i consider something? 我可以像在我的普通流中那样写它或者我应该考虑一下吗?


static void Main(string[] args)
{
    var tcpServer = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
    tcpServer.Start();
    while (true)
    {
        var proxyClient = tcpServer.AcceptTcpClient();
        var requestClient = new TcpClient();
        var proxyStream = proxyClient.GetStream();
        NetworkStream requestStream = null;
        var bytes = new byte[proxyClient.ReceiveBufferSize];
        var hostHeaderAvailable = 0;
        int count;

        while (proxyStream.DataAvailable)
        {
            count = proxyStream.Read(bytes, 0, bytes.Length);
            if (hostHeaderAvailable == 0)
            {
                var text = Encoding.UTF8.GetString(bytes);
                const string connectText = "connect";
                const string hostText = "Host: ";
                //HTTPS NOT FULLY IMPLEMENTED YET
                if (text.ToLower().StartsWith(connectText))
                {
                    var host = text.Remove(0, connectText.Length + 1);
                    var hostIndex = host.IndexOf(" ", StringComparison.Ordinal);
                    var hostEntry = host.Remove(hostIndex).Split(new []{":"}, StringSplitOptions.None);
                    requestClient.Connect(hostEntry[0], Convert.ToInt32(hostEntry[1]));
                    requestStream = requestClient.GetStream();
                    var sslStream = new SslStream(requestStream, false, (x1,x2,x3,x4) => true);
                    sslStream.AuthenticateAsClient(hostEntry[0]);
                    const string sslResponse = "HTTP/1.0 200 Connection established\r\n\r\n";
                    var sslResponseBytes = Encoding.UTF8.GetBytes(sslResponse);
                    proxyStream.Write(sslResponseBytes, 0, sslResponseBytes.Length);
                    proxyStream.Flush();
                }
                //HTTP WORKS LIKE A CHARM
                else {
                    var hostIndex = text.IndexOf(hostText, StringComparison.Ordinal);
                    if (hostIndex < 0)
                        continue;
                    var host = text.Remove(0, hostIndex + hostText.Length);
                    hostIndex = host.IndexOf("\n", StringComparison.Ordinal);
                    if (hostIndex < 0)
                        continue;
                    host = host.Remove(hostIndex).Replace("\r", "");
                    requestClient.Connect(host, 80);
                    requestStream = requestClient.GetStream();
                }
            }
            hostHeaderAvailable++;
            if (requestClient.Connected) {
                requestStream.Write(bytes, 0, count);
            }
        }

        if (!requestClient.Connected) {
            proxyStream.Close();
            proxyClient.Close();
            continue;
        }

        var timeout = 0;
        while (!requestStream.DataAvailable) {
            if (timeout > 12)
                break;
            Thread.Sleep(500);
            timeout++;
        }

        while (requestStream.DataAvailable)
        {
            count = requestStream.Read(bytes, 0, bytes.Length);
            proxyStream.Write(bytes, 0, count);
        }
        proxyStream.Close();
        proxyClient.Close();
    }
}

IE issues a CONNECT request to my proxy My proxy sees that its a CONNECT request and gets the ip:port of the destination (eg, www.hotmail.com:443) My proxy creates a new TCP connection to www.hotmail.com:443 IE向我的代理发出CONNECT请求我的代理看到它是一个CONNECT请求并获取目标的ip:端口(例如,www.hotmail.com:443)我的代理创建了一个到www.hotmail.com的新TCP连接: 443

All correct so far. 到目前为止一切正确。

My proxy gets an SslStream from this destination and calls AuthenticateAsClient - this gives my proxy a secure connection to the hotmail side of things 我的代理从这个目的地获取一个SslStream并调用AuthenticateAsClient - 这使我的代理与Hotmail方面的安全连接

No. Your proxy should use the plain-text connection you already have. 不可以。您的代理人应该使用您已有的纯文本连接。

My proxy then sends an "HTTP/1.0 200" message back to the browser to say that the CONNECT was successful. 我的代理然后将“HTTP / 1.0 200”消息发送回浏览器以表示CONNECT成功。

Correct. 正确。 Or else if you got a connection failure you send back an appropriate HTTP failure response. 否则,如果连接失败,则会发回适当的HTTP失败响应。

My proxy then gets an SslStream from the browser connection and calls AuthenticateAsServer - gives my proxy a secure connection to the browser side of things 我的代理然后从浏览器连接获取SslStream并调用AuthenticateAsServer - 为我的代理提供与浏览器端的安全连接

No. Your proxy continues to use the plaintext connection to the browser. 不可以。您的代理继续使用与浏览器的纯文本连接。

how AuthenticateAsServer without fake certificate? AuthenticateAsServer如何没有假证书?

You don't have to do it at all. 你根本不需要这样做。

At this point the browser and the upstream server are ready to execute the SSL handshake. 此时,浏览器和上游服务器已准备好执行SSL握手。 But as you said you don't want to sniff the contents, you have no need to be an SSL endpoint yourself. 但正如您所说,您不想嗅探内容,您不需要自己成为SSL端点。 All you have to do now is copy bytes in both directions simultaneously. 您现在要做的就是同时复制两个方向的字节。 The endpoints will SSL-handshake just as though you weren't there. 端点将进行SSL握手,就像您不在那里一样。

Adding to the answer from EJP, the proxy simply opens a tunnel between the end server and the client after a successful CONNECT request. 从EJP添加答案后,代理只需在成功的CONNECT请求后打开终端服务器和客户端之间的隧道。 The client however, needs to upgrade the socket to HTTPS and continue sending data through the same socket which was used in the CONNECT request. 但是,客户端需要将套接字升级到HTTPS并继续通过CONNECT请求中使用的同一套接字发送数据。 The proxy on the other hand just needs to maintain this tunnel between the end server and client acting as a simple simple transparent proxy just copying encrypted data from one socket to another. 另一方面,代理只需要在端服务器和客户端之间维护这个隧道,作为一个简单的简单透明代理,只需将加密数据从一个套接字复制到另一个套接字。

Check this doc for more details about the tunnel 有关隧道的更多详细信息,请查看此文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM