Golang中如何解密HTTPS数据包

Golang中如何解密HTTPS数据包 你好,使用 Golang 我可以通过 gopacket 获取 HTTP 数据包。我拥有一个证书,想要获取 HTTPS 数据包,但我无法解密这些数据包?

3 回复

HTTPS的目的就是不允许解密数据包。

更多关于Golang中如何解密HTTPS数据包的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Cengiz,你最好先了解一下公私钥加密的工作原理:https://en.wikipedia.org/wiki/Public-key_cryptography

然后看看这个例子:

gist.github.com

https://gist.github.com/denji/12b3a568f092ab951456

golang-tls.md
# Moved to git repository: https://github.com/denji/golang-tls

##### Generate private key (.key)

```sh
# Key considerations for algorithm "RSA" ≥ 2048-bit
openssl genrsa -out server.key 2048

# Key considerations for algorithm "ECDSA" ≥ secp384r1
# List ECDSA the supported curves (openssl ecparam -list_curves)

此文件已被截断。显示原文

在Golang中解密HTTPS数据包需要使用TLS密钥日志功能配合Wireshark,或者使用中间人代理方式。以下是两种实现方案:

方案一:使用TLS密钥日志(推荐)

通过设置SSLKEYLOGFILE环境变量,Go程序会输出TLS会话密钥,然后使用Wireshark解密:

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
)

func main() {
    // 设置SSLKEYLOGFILE环境变量
    os.Setenv("SSLKEYLOGFILE", "/tmp/sslkey.log")
    
    // 创建自定义Transport以支持密钥日志
    transport := &http.Transport{
        TLSClientConfig: &tls.Config{
            KeyLogWriter: io.Discard, // 实际密钥会自动写入SSLKEYLOGFILE
        },
    }
    
    client := &http.Client{Transport: transport}
    
    resp, err := client.Get("https://example.com")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    
    body, _ := io.ReadAll(resp.Body)
    fmt.Printf("Response length: %d\n", len(body))
}

然后在Wireshark中:

  1. 编辑 → 首选项 → Protocols → TLS
  2. 设置"(Pre)-Master-Secret log filename"为/tmp/sslkey.log
  3. 捕获流量并解密

方案二:中间人代理实现

创建TLS中间人代理来解密HTTPS流量:

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "net/http/httputil"
)

// 生成自签名证书(实际使用需要有效证书)
var cert = `-----BEGIN CERTIFICATE-----
MIIC...(证书内容)
-----END CERTIFICATE-----`

var key = `-----BEGIN PRIVATE KEY-----
MII...(私钥内容)
-----END PRIVATE KEY-----`

func handleTunneling(w http.ResponseWriter, r *http.Request) {
    destConn, err := net.DialTimeout("tcp", r.Host, 10*1000*1000*1000)
    if err != nil {
        http.Error(w, err.Error(), http.StatusServiceUnavailable)
        return
    }
    w.WriteHeader(http.StatusOK)
    
    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)
    }
    
    go transfer(destConn, clientConn)
    go transfer(clientConn, destConn)
}

func transfer(destination io.WriteCloser, source io.ReadCloser) {
    defer destination.Close()
    defer source.Close()
    io.Copy(destination, source)
}

func handleHTTP(w http.ResponseWriter, req *http.Request) {
    // 解密并记录请求
    dump, _ := httputil.DumpRequest(req, true)
    fmt.Printf("Decrypted request:\n%s\n", string(dump))
    
    // 转发请求到目标服务器
    resp, err := http.DefaultTransport.RoundTrip(req)
    if err != nil {
        http.Error(w, err.Error(), http.StatusServiceUnavailable)
        return
    }
    defer resp.Body.Close()
    
    // 复制响应头
    for k, vv := range resp.Header {
        for _, v := range vv {
            w.Header().Add(k, v)
        }
    }
    w.WriteHeader(resp.StatusCode)
    io.Copy(w, resp.Body)
}

func main() {
    // 加载证书
    cert, err := tls.X509KeyPair([]byte(cert), []byte(key))
    if err != nil {
        log.Fatal(err)
    }
    
    server := &http.Server{
        Addr: ":8888",
        Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if r.Method == http.MethodConnect {
                handleTunneling(w, r)
            } else {
                handleHTTP(w, r)
            }
        }),
        TLSConfig: &tls.Config{
            Certificates: []tls.Certificate{cert},
        },
    }
    
    log.Fatal(server.ListenAndServeTLS("", ""))
}

配合gopacket捕获和解密

package main

import (
    "github.com/google/gopacket"
    "github.com/google/gopacket/pcap"
    "log"
)

func main() {
    handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()
    
    // 设置BPF过滤器捕获TLS流量
    err = handle.SetBPFFilter("tcp port 443")
    if err != nil {
        log.Fatal(err)
    }
    
    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    for packet := range packetSource.Packets() {
        // 这里可以配合密钥日志文件解析TLS流量
        fmt.Printf("Packet: %v\n", packet)
    }
}

使用mitmproxy库

package main

import (
    "github.com/lqqyt2423/go-mitmproxy/proxy"
    "log"
)

func main() {
    opts := &proxy.Options{
        Addr:              ":8080",
        StreamLargeBodies: 1024 * 1024 * 5,
    }
    
    p, err := proxy.NewProxy(opts)
    if err != nil {
        log.Fatal(err)
    }
    
    // 添加请求/响应处理函数
    p.AddAddon(&proxy.LogAddon{})
    
    log.Fatal(p.Start())
}

运行后配置系统或浏览器代理为localhost:8080,所有HTTPS流量将通过代理解密。

关键点:

  1. 方案一需要客户端支持SSLKEYLOGFILE
  2. 方案二需要客户端信任中间人证书
  3. 实际解密需要合法授权和证书
  4. gopacket本身不提供TLS解密功能,需配合其他工具
回到顶部