ホームページ  >  記事  >  バックエンド開発  >  golang トラフィック https 転送

golang トラフィック https 転送

王林
王林オリジナル
2023-05-10 09:17:06911ブラウズ

インターネット セキュリティがますます重視されるようになり、ユーザーのアクセス通信を保護するために HTTPS を使用する Web サイトが増えています。ただし、特定のシナリオでは、特定の要件を達成するためにプロキシを使用してトラフィックを転送する必要があります。この記事では、golang を使用して HTTPS トラフィックを転送できるプロキシ サーバーを作成する方法を紹介します。

1. HTTP プロキシの実装

まず、golang が HTTP プロキシを実装する方法を紹介します。

Golang の標準ライブラリは net/http/httputil パッケージを提供します。このパッケージには、ReverseProxy や DumpRequestOut などの HTTP プロキシの実装に必要なツールと関数がカプセル化されています。 ReverseProxy は、受信した要求を別の HTTP サーバーに転送できるリバース プロキシ サーバーを表します。 DumpRequestOut 関数は、リクエストが送信される前にリクエストの内容をバイナリ形式でエンコードして出力できるため、リダイレクトされた Web サイトのプロセスとインタラクションの詳細を理解するのに役立ちます。

次のコードを使用して、単純な HTTP プロキシを実装できます:

package main

import (
    "log"
    "net/http"
    "net/http/httputil"
)

func main() {
    proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: "http", Host: "localhost:8080"})
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        proxy.ServeHTTP(w, r)
    })
    log.Fatal(http.ListenAndServe(":10080", nil))
}

上記のコードでは、リバース プロキシ サーバーを作成し、受信したリクエストを http:// localhost:8080 に転送します。 、サーバーはポート 10080 で監視されます。 HTTP リクエストをプロキシ サーバーに送信すると、プロキシ サーバーはリクエストをローカル ポート 8080 に転送し、コンソールに出力します。

2. HTTPS プロキシの実装

次に、golang を使用して HTTPS プロキシを実装し、HTTPS トラフィックを転送できるようにする方法を紹介します。まず、安全な HTTPS 通信のために証明書を使用する必要があります。

1. 自己署名証明書の生成

openssl を使用して、テスト環境で HTTPS 通信用の自己署名証明書を生成できます。具体的な手順は次のとおりです。

ステップ 1: 秘密鍵 key.pem

openssl genrsa -out key.pem 2048
を生成します。

ステップ 2: 証明書要求証明書 csr.pem

openssl req -new -key key.pem -out csr.pem
を生成します。上記を通過した後、 2 つのステップで、自己署名証明書を作成するための秘密キーと証明書要求ファイルを作成しました。

ステップ 3: 証明書 crt.pem を生成する

csr.pem と key.pem を使用して自己署名証明書を生成できます:

openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out crt.pem

このステップでは、 365 日の期限が使用され、証明書 crt.pem が生成されました。

この時点で、自己署名証明書が作成され、HTTPS 通信に使用できるようになりました。

2. HTTPS プロキシの実装

まず、クライアントのリクエストを解析し、対応するヘッダーを読み取り、クライアントがリクエストしたホスト アドレスを取得する必要があります。次に、クライアントの TLS 接続を作成し、ハンドシェイクが成功した後にターゲット サーバーに転送します。 Windows および macOS システムでは、TLS の最小バージョンを 1.1 に指定する必要があることに注意してください。1.1 に指定しないと、接続が強制的に閉じられます。

次に、HTTPS プロキシのコード例を示します。

package main

import (
    "log"
    "net"
    "net/http"
    "net/http/httputil"
    "time"
)

func main() {
    // 代理的目标
    target := "http://localhost:8080"
    // 对HTTPS请求使用自签名证书
    certFile, keyFile := "crt.pem", "key.pem"
    cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        log.Fatal(err)
    }

    // 创建TLS配置
    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cert},
        MinVersion:   tls.VersionTLS11,
    }

    // 创建反向代理
    proxy := httputil.NewSingleHostReverseProxy(&url.URL{
        Scheme: "http",
        Host:   "localhost:8080",
    })

    // 处理CONNECT请求
    handleConnect := func(w http.ResponseWriter, r *http.Request) {
        // 解析主机地址
        host, _, err := net.SplitHostPort(r.Host)
        if err != nil {
            http.Error(w, fmt.Sprintf("Invalid host: %s", err), http.StatusBadRequest)
            return
        }

        // 创建目标地址
        targetHost := net.JoinHostPort(host, "443")

        // 设置超时时间为10s
        dialer := &net.Dialer{
            Timeout: 10 * time.Second,
        }

        // 创建TLS连接
        conn, err := tls.DialWithDialer(dialer, "tcp", targetHost, tlsConfig)
        if err != nil {
            http.Error(w, fmt.Sprintf("Unable to create TLS connection: %s", err), http.StatusServiceUnavailable)
            return
        }

        // 将握手成功的连接转发到目标服务器
        hijacker, ok := w.(http.Hijacker)
        if !ok {
            http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
            return
        }
        clientConn, _, err := hijacker.Hijack()
        if err != nil {
            http.Error(w, err.Error(), http.StatusServiceUnavailable)
            return
        }

        // 向客户端发送连接成功的状态码
        clientConn.Write([]byte("HTTP/1.1 200 Connection Established

"))

        // 进行双向数据拷贝
        go func() {
            defer conn.Close()
            io.Copy(conn, clientConn)
        }()
        go func() {
            defer clientConn.Close()
            io.Copy(clientConn, conn)
        }()
    }

    // 设置HandlerFunc
    handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.Method == http.MethodConnect {
            handleConnect(w, r)
            return
        }
        proxy.ServeHTTP(w, r)
    })

    // 监听
    server := &http.Server{
        Addr:         ":10080",
        Handler:      handlerFunc,
        TLSConfig:    tlsConfig,
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
    }
    log.Fatal(server.ListenAndServeTLS("", ""))
}

上記のコードは、基本的な HTTPS プロキシ サーバーを実装し、受信した HTTPS リクエストをターゲット サーバーに転送できます。なお、実際の運用においては、HTTPSのセキュリティを強化するためにCA発行の証明書を利用するなど、実際のニーズに応じた調整が必要となります。

3. 概要

この記事では、golang を使用してプロキシ サーバーを実装し、HTTP および HTTPS プロトコルのトラフィック転送を完了する方法を紹介しました。ネットワーク トラフィックを転送する必要がある場合、プロキシ サーバーを実装すると、目標を適切に達成することができ、ネットワーク通信プロトコルの理解と応用も向上します。

以上がgolang トラフィック https 転送の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。