Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confirm TLS certificate while performing ReverseProxy in GoLang

In Go I'm using NewSingleHostReverseProxy to perform a reverse proxy, however I need to confirm the SSL certificates of the host site, to make sure I have the correct secure certificate... any ideas how I should do this? Should I be doing this with the handler or transport? I'm new to Go and still getting my head around it.

proxy := httputil.NewSingleHostReverseProxy(&url.URL{
         Scheme: "https",
         Host:   "sha256.badssl.com",
})

http.ListenAndServe("127.0.0.1:80", proxy)
like image 544
user2257892 Avatar asked Feb 14 '16 10:02

user2257892


2 Answers

To access the certificate, you will have get access to the ConnectionState. The easiest way to do that is to provide your own version of DialTLS. In there you connect to the server using net.Dial, do the TLS handshake and then you are free to verify.

package main

import (
    "crypto/tls"
    "log"
    "net"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    proxy := httputil.NewSingleHostReverseProxy(&url.URL{
        Scheme: "https",
        Host:   "sha256.badssl.com",
    })

    // Set a custom DialTLS to access the TLS connection state
    proxy.Transport = &http.Transport{DialTLS: dialTLS}

    // Change req.Host so badssl.com host check is passed
    director := proxy.Director
    proxy.Director = func(req *http.Request) {
        director(req)
        req.Host = req.URL.Host
    }

    log.Fatal(http.ListenAndServe("127.0.0.1:3000", proxy))
}

func dialTLS(network, addr string) (net.Conn, error) {
    conn, err := net.Dial(network, addr)
    if err != nil {
        return nil, err
    }

    host, _, err := net.SplitHostPort(addr)
    if err != nil {
        return nil, err
    }
    cfg := &tls.Config{ServerName: host}

    tlsConn := tls.Client(conn, cfg)
    if err := tlsConn.Handshake(); err != nil {
        conn.Close()
        return nil, err
    }

    cs := tlsConn.ConnectionState()
    cert := cs.PeerCertificates[0]

    // Verify here
    cert.VerifyHostname(host)
    log.Println(cert.Subject)

    return tlsConn, nil
}
like image 50
Danilo Avatar answered Sep 24 '22 20:09

Danilo


To tweak the SSL to the Reverse Host, it is possible to set the transport options. So if you want to skip the verify you can set it like this.

proxy := httputil.NewSingleHostReverseProxy(&url.URL{
         Scheme: "https",
         Host:   "sha256.badssl.com",
})

proxy.Transport = &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

http.ListenAndServe("127.0.0.1:80", proxy)
like image 45
Alex Avatar answered Sep 25 '22 20:09

Alex