Golang中如何解密HTTPS数据包
Golang中如何解密HTTPS数据包 你好,使用 Golang 我可以通过 gopacket 获取 HTTP 数据包。我拥有一个证书,想要获取 HTTPS 数据包,但我无法解密这些数据包?
3 回复
Cengiz,你最好先了解一下公私钥加密的工作原理:https://en.wikipedia.org/wiki/Public-key_cryptography
然后看看这个例子:
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中:
- 编辑 → 首选项 → Protocols → TLS
- 设置"(Pre)-Master-Secret log filename"为
/tmp/sslkey.log - 捕获流量并解密
方案二:中间人代理实现
创建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流量将通过代理解密。
关键点:
- 方案一需要客户端支持SSLKEYLOGFILE
- 方案二需要客户端信任中间人证书
- 实际解密需要合法授权和证书
- gopacket本身不提供TLS解密功能,需配合其他工具

