2

クライアントからのセキュリティで保護されていない http トラフィックをセキュリティで保護された https トラフィックとしてサーバーに転送し、再び戻す透過的なプロキシを開発しようとしています。私の主張をよりよく説明するために、次の画像を見てください。

リッチピクチャー

さまざまな理由で、クライアントが HTTP のみを使用し、HTTPS にポート 443 を使用できないとします。一部のサーバーはポート 80 からのトラフィックを受け入れないため、プロキシはそれらをポート 443 に再ルーティングする必要があります。これは考えられるシナリオです。

  1. www.google.com に向かってポート 80 に向かうクライアントからデータを受信します。
  2. https://www.google.comとの接続をポート 443 に初期化します (ハンドシェイクなどを行います)
  3. クライアントからのデータを暗号化し、https://www.google.comのポート 443 に送信します。
  4. https://www.google.comから応答を受け取り、それらを復号化し、クライアントのポート 80 に送り返します。

これは透過的なプロキシであるため、クライアント (私の場合は多数) に追加の構成は必要ありません。トラフィックがノードを通過するように、ネットワークはすでに構成されています。現在、私のノードは単にデータを再ルーティングし、ウイルスが含まれている場合は一部をブロックします。これは、WinPcapを使用して下位のネットワーク レイヤーにアクセスすることによって行われますが、生のパケットを使用して行うのが難しすぎる場合 (主にハンドシェイクが懸念されます)、アプローチを変更してもかまいません。

私が試したこと: 注: www.google.com は、ウェブ上の任意のサイトである可能性があります。これは単に例として使用されています。

  1. イリジウムの提案。別のアプリケーションが TcpClient を使用して接続する場合、TcpListener は新しい接続のみを受け入れるため、これは機能しません。これは透過プロキシであるため、機能しません。
  2. 代わりに HttpListener を使用します。ただし、自分の IP (www.google.com ではなく) への接続のみを受け入れるため、これは機能しないようです。
  3. 前と同じように HttpListener を使用しますが、今回はパケットを自分の IP に転送して、HttpListener が接続を受け入れるようにします。何らかの理由で、これは機能していないようです (wireshark を介して検査すると、TCP SYN パケットが再送信され続けますが、理由や修正方法がわかりません)。
  4. SslStream を使用してhttps://www.google.comに接続し、クライアントから受信した生のパケットからコンテンツを取得してストリームに書き込みます。SslStream は TCP パケット (ACK や SYN など) を単独で処理するため、これは機能しません。ストリームは Http リクエストのみを想定しています。それが機能しないもう 1 つの理由は、ストリームから TCP パケットの内容を読み取ることができず、HTTP 応答の内容しか読み取れないためです (したがって、クライアントはそこに座って ACK を待っています)。
  5. クライアントからの TCP パケットをそのままポート 443 に転送し、サーバーからポート 80 に転送し (HTTP 要求と応答のみが SSL で暗号化されるため、違いはありません)、HttpRequest クラスを使用してすべての http 要求を作成します。および応答 (クラスが独自にハンドシェイクを処理するため)。両側で ACK が間違っているため、これは機能しません。

そのようなプロキシを開発するための最良の方法は何でしょうか?

編集: TcpListener または HttpListener が透過プロキシとして機能する方法はありますか? (クライアントのコンピューターでの構成なし)。クライアントが接続しようとしていることを HttpListener が正確に認識するのはいつですか?

4

1 に答える 1

0

から暗号化されたデータを読み取る必要がある理由がよくわかりませんSslStream。私があなたの説明を正しく読んでいれば、次のことを行う必要があります。

  • クライアント接続を待つ
  • クライアントが接続したら、サーバーに接続します
  • サーバー接続をNetworkStreamand でSslStream囲みますAuthenticateAsClient
  • 認証後、並行して:
    • クライアントからデータを読み取り、SslStream
    • からデータを読み取りSslStream、クライアントに書き込みます

このプロセスのどこにも、暗号化されたデータを表示する必要がある箇所はありませんSslStream

以下は非常に基本的なサンプルです (ただし、完全にテストされていません)。

static void Main(string[] args)
{
    var listener = new TcpListener(IPAddress.Any, 11180);
    var clientConnection = listener.AcceptTcpClient();
    // When we get here, the client has connected, initiate the server connection
    var serverConnection = new TcpClient("your.server.name", 443);
    var serverStream = serverConnection.GetStream();
    var secureStream = new SslStream(serverStream);
    secureStream.AuthenticateAsClient("your.server.name");
    ConnectStreams(clientConnection.GetStream(), secureStream);
}

private static void ConnectStreams(Stream streamA, Stream streamB)
{
    ForwardStream(streamA, streamB, new byte[1024]);
    ForwardStream(streamB, streamA, new byte[1024]);
}

private static void ForwardStream(Stream source, Stream destination, byte[] buffer)
{
    source.BeginRead(buffer, 0, buffer.Length, r => Forward(source, destination, r, buffer), null);
}

private static void Forward(Stream source, Stream destination, IAsyncResult asyncResult, byte[] buffer)
{
    var bytesRead = source.EndRead(asyncResult);
    if (bytesRead == 0)
    {
        destination.Close();
        return;
    }
    destination.Write(buffer, 0, bytesRead);
    ForwardStream(source, destination, buffer);
}
于 2013-04-19T15:42:06.117 に答える