[英]HTTPS Proxy Implementation (SSLStream)
我編寫了一個充當代理服務器的控制台應用程序。 現在我也想實現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傳遞證書嗎?
我看到了這個,但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)我的代理創建了一個到www.hotmail.com的新TCP連接: 443
到目前為止一切正確。
我的代理從這個目的地獲取一個SslStream並調用AuthenticateAsClient - 這使我的代理與Hotmail方面的安全連接
不可以。您的代理人應該使用您已有的純文本連接。
我的代理然后將“HTTP / 1.0 200”消息發送回瀏覽器以表示CONNECT成功。
正確。 否則,如果連接失敗,則會發回適當的HTTP失敗響應。
我的代理然后從瀏覽器連接獲取SslStream並調用AuthenticateAsServer - 為我的代理提供與瀏覽器端的安全連接
不可以。您的代理繼續使用與瀏覽器的純文本連接。
AuthenticateAsServer如何沒有假證書?
你根本不需要這樣做。
此時,瀏覽器和上游服務器已准備好執行SSL握手。 但正如您所說,您不想嗅探內容,您不需要自己成為SSL端點。 您現在要做的就是同時復制兩個方向的字節。 端點將進行SSL握手,就像您不在那里一樣。
從EJP添加答案后,代理只需在成功的CONNECT請求后打開終端服務器和客戶端之間的隧道。 但是,客戶端需要將套接字升級到HTTPS並繼續通過CONNECT請求中使用的同一套接字發送數據。 另一方面,代理只需要在端服務器和客戶端之間維護這個隧道,作為一個簡單的簡單透明代理,只需將加密數據從一個套接字復制到另一個套接字。
有關隧道的更多詳細信息,請查看此文檔
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.