HTTPS代理实现(SSLStream)
本文关键字:SSLStream 实现 代理 HTTPS | 更新日期: 2023-09-27 18:08:37
我编写了一个控制台应用程序作为代理服务器。现在我也想实现SSL。不喜欢解密任何流量。就像普通的https代理一样。我不知道该怎么继续下去。
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();
我应该直接写一切到sslStream?浏览器连接proxyClient
怎么样?我是否需要包装流,或者我可以直接将所有内容写入proxyStream
?我应该使用AuthenticateAsServer并以某种方式从AuthenticateAsClient传递证书吗?
- IE向我的代理发出CONNECT请求
- 我的代理看到它是一个连接请求,并获得的IP:端口目的地(例如www.hotmail.com:443)
- 我的代理创建一个新的TCP连接到www.hotmail.com:443
- 我的代理从这个目的地获得一个SslStream并调用AuthenticateAsClient -这给了我的代理一个安全的连接到Hotmail的东西 然后我的代理发送一个"HTTP/1.0 200"消息回浏览器,说连接成功。
- 我的代理然后从浏览器连接中获得一个SslStream并调用AuthenticateAsServer -给我的代理一个安全的连接到浏览器端
我看到了这个,但是如何AuthenticateAsServer没有假证书。我能把它写成正常的格式吗还是我应该考虑别的?
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向我的代理发出CONNECT请求我的代理看到它是一个CONNECT请求,并获得目的地的ip:端口(例如,www.hotmail.com:443)我的代理创建一个新的TCP连接到www.hotmail.com:443
到目前为止都正确。
我的代理从这个目的地获得一个SslStream并调用AuthenticateAsClient -这给了我的代理一个安全的连接到hotmail的东西
。您的代理应该使用您已有的纯文本连接。
我的代理然后发送一个"HTTP/1.0 200"消息回浏览器,说连接成功。
正确的。否则,如果你有一个连接失败,你发回一个适当的HTTP失败响应。
我的代理然后从浏览器连接中获得SslStream并调用AuthenticateAsServer -为我的代理提供到浏览器端的安全连接
。您的代理继续使用明文连接到浏览器。
如何AuthenticateAsServer没有假证书?
你根本不需要做这件事。
此时,浏览器和上游服务器已经准备好执行SSL握手。但是正如您所说的,您不想嗅探内容,因此您不需要自己成为SSL端点。现在你所要做的就是同时在两个方向上复制字节。终端将进行ssl握手,就像您不存在一样。除了EJP的应答之外,代理只是在成功发出CONNECT请求后在终端服务器和客户端之间打开一条隧道。然而,客户端需要将套接字升级到HTTPS,并通过CONNECT请求中使用的套接字继续发送数据。另一方面,代理只需要维护终端服务器和客户端之间的通道,就像一个简单的透明代理一样,只需要将加密数据从一个套接字复制到另一个套接字。
查看此文档了解更多关于隧道的详细信息