Maison  >  Article  >  développement back-end  >  transfert https du trafic Golang

transfert https du trafic Golang

王林
王林original
2023-05-10 09:17:06844parcourir

Avec l’accent croissant mis sur la sécurité Internet, de plus en plus de sites Web commencent à utiliser HTTPS pour protéger les communications d’accès des utilisateurs. Cependant, dans certains scénarios spécifiques, nous devons utiliser un proxy pour transférer le trafic afin de répondre à certaines exigences spécifiques. Cet article explique comment utiliser Golang pour écrire un serveur proxy capable de transférer le trafic HTTPS.

1. Implémentation du proxy HTTP

Tout d'abord, présentons comment Golang implémente un proxy HTTP.

La bibliothèque standard de Golang fournit le package net/http/httputil, qui encapsule les outils et fonctions nécessaires à la mise en œuvre du proxy HTTP, tels que ReverseProxy et DumpRequestOut. ReverseProxy représente un serveur proxy inverse qui peut transférer les requêtes reçues vers un autre serveur HTTP. La fonction DumpRequestOut peut encoder et afficher le contenu de la demande dans un format binaire avant que la demande ne soit envoyée. Cela nous aidera à comprendre les détails du processus et de l'interaction du site Web redirigé.

Nous pouvons utiliser le code suivant pour implémenter un simple proxy 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))
}

Dans le code ci-dessus, nous créons un serveur proxy inverse, transmettons la requête reçue à http://localhost:8080 et envoyons le serveur en écoute sur le port 10080. Lorsque nous envoyons une requête HTTP au serveur proxy, le serveur proxy transmettra la requête au port local 8080 et l'affichera sur la console.

2. Implémentation du proxy HTTPS

Ensuite, nous présenterons comment utiliser Golang pour implémenter un proxy HTTPS afin qu'il puisse transférer le trafic HTTPS. Tout d’abord, nous devons utiliser un certificat pour une communication HTTPS sécurisée.

1. Génération de certificat auto-signé

Nous pouvons utiliser openssl pour générer un certificat auto-signé pour la communication HTTPS dans l'environnement de test. Les étapes spécifiques sont les suivantes :

Étape 1 : Générer une clé privée key.pem

openssl genrsa -out key.pem 2048

Étape 2 : Générer un certificat de demande de certificat csr.pem

openssl req -new -key key.pem -out csr.pem

Grâce aux deux étapes ci-dessus, nous avons créé une clé privée et l'avons utilisée pour créer un fichier de demande d’auto-certificat pour le certificat signataire.

Étape 3 : Générer le certificat crt.pem

Nous pouvons utiliser csr.pem et key.pem pour générer un certificat auto-signé :

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

Dans cette étape, nous utilisons un délai de 365 jours et générons le certificat crt .pem.

À ce stade, nous avons créé un certificat auto-signé et pouvons l'utiliser pour la communication HTTPS.

2. Implémenter le proxy HTTPS

Nous devons d'abord analyser la demande du client et lire ses en-têtes correspondants pour obtenir l'adresse hôte demandée par le client. Nous pouvons ensuite créer une connexion TLS pour le client et la transmettre au serveur cible après une négociation réussie. Il convient de noter que sur les systèmes Windows et macOS, la version minimale de TLS doit être spécifiée comme 1.1, sinon la connexion sera fermée de force.

Ce qui suit est un exemple de code de proxy 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("", ""))
}

Le code ci-dessus implémente un serveur proxy HTTPS de base et peut transmettre les requêtes HTTPS reçues au serveur cible. Il convient de noter que lors de l'utilisation réelle, nous devons procéder aux ajustements correspondants en fonction des besoins réels, par exemple en utilisant des certificats délivrés par CA pour renforcer la sécurité du HTTPS.

3. Résumé

Dans cet article, nous avons présenté comment utiliser Golang pour implémenter un serveur proxy et compléter le transfert du trafic des protocoles HTTP et HTTPS. En ce qui concerne la nécessité de transférer le trafic réseau, la mise en œuvre d'un serveur proxy peut nous aider à bien atteindre notre objectif et améliore également notre compréhension et notre application des protocoles de communication réseau.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn