1.1. 介绍

goproxy - An HTTP proxy library for Go

可参考文档:goproxy

简单来说,就是GO实现的http代理,可以从中间操作经过的数据包;劫持到的数据包就是一个net/http的实例

1.2. 安装

我直接用go get搞不下来了,不知道是不是GO1.18的问题,所以这里我直接git clone下来,放到对应的src目录即可

mkdir $GOPATH/src/github.com/elazarl
cd elazarl
git clone https://github.com/elazarl/goproxy

1.3. 快速入门

直接用readme中的例子,其中DoFunc是对数据包进行二次处理。

package main

import (
    "github.com/elazarl/goproxy"
    "log"
    "net/http"
)

func main() {
    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = true

    proxy.OnRequest().DoFunc(
        func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {
            // 添加Header头
            r.Header.Set("X-GoProxy","yxorPoG-X")
            return r,nil
        })

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

跑起来,本地监听80端口,然后用curl发起请求

curl -x http://127.0.0.1:8080 http://127.0.0.1

查看收到的数据包,是我想要的效果,大功告成。

image-20220618172849772

1.4. 常见用法

各种例子:examples

上面用了一个proxy.OnRequest(),其他的直接从文档里面复制过来了

There are 3 kinds of useful handlers to manipulate the behavior, as follows:

// handler called after receiving HTTP CONNECT from the client, and before proxy establish connection 
// with destination host
httpsHandlers   []HttpsHandler

// handler called before proxy send HTTP request to destination host
reqHandlers     []ReqHandler 

// handler called after proxy receives HTTP Response from destination host, and before proxy forward 
// the Response to the client.
respHandlers    []RespHandler

Depending on what you want to manipulate, the ways to add handlers to each handler list are:

// Add handlers to httpsHandlers 
proxy.OnRequest(Some ReqConditions).HandleConnect(YourHandlerFunc())

// Add handlers to reqHandlers
proxy.OnRequest(Some ReqConditions).Do(YourReqHandlerFunc())

// Add handlers to respHandlers
proxy.OnResponse(Some RespConditions).Do(YourRespHandlerFunc())

For example:

// This rejects the HTTPS request to *.reddit.com during HTTP CONNECT phase
proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("reddit.*:443$"))).HandleConnect(goproxy.AlwaysReject)

// This will NOT reject the HTTPS request with URL ending with gif, due to the fact that proxy 
// only got the URL.Hostname and URL.Port during the HTTP CONNECT phase if the scheme is HTTPS, which is
// quiet common these days.
proxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).HandleConnect(goproxy.AlwaysReject)

// The correct way to manipulate the HTTP request using URL.Path as condition is:
proxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).Do(YourReqHandlerFunc())

1.5. 代理HTTPS

要获取到https流量,都需要在客户端安装信任 CA 证书

1.5.1. 生成自签名证书

使用goproxy自带的生成脚本,路径为github.com/elazarl/goproxy/certs,可以自己修改openssl.cnf的配置

sh openssl-gen.sh

image-20220618190828103

会在当前目录生成ca.pemca.key.pem,macos直接双击安装ca.pem到钥匙串并完全信任,windows后缀名改为.crt双击安装并分类到系统根证书

image-20220618190929692

1.5.2. 设置代理证书

设置证书代码参考:github.com/elazarl/goproxy/examples/goproxy-customca/cert.go

package main

import (
    "crypto/tls"
    "crypto/x509"
    "github.com/elazarl/goproxy"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)

/*
设置代理证书,caCert和caKey就是刚才生成的pem文件内容
 */
func setCA(caCert, caKey []byte) error {
    goproxyCa, err := tls.X509KeyPair(caCert, caKey)
    if err != nil {
        return err
    }
    if goproxyCa.Leaf, err = x509.ParseCertificate(goproxyCa.Certificate[0]); err != nil {
        return err
    }
    goproxy.GoproxyCa = goproxyCa
    goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
    return nil
}

func main() {
    pwd, _ := os.Getwd()
    caCert, _ := ioutil.ReadFile(pwd + "/ca.pem") // 设置为你刚才生成的 ca.pem 路径
    caKey, _ := ioutil.ReadFile(pwd + "/ca.key.pem")  // 设置为你刚才生成的 ca.key.pem 路径
    setCA(caCert, caKey)

    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = true

    proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
    proxy.OnRequest().DoFunc(
        func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {
            // 添加Header头
            r.Header.Set("X-GoProxy","yxorPoG-X")
            return r,nil
        })
    proxy.OnResponse().DoFunc(
        func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
            // 返回包状态码修改
            resp.StatusCode = 404
            return resp
    })
    log.Fatal(http.ListenAndServe(":8080", proxy))
}

启动后curl试试,发现已经OK了

curl -x http://127.0.0.1:8080 https://blog.gm7.org/

image-20220618191526478

Copyright © d4m1ts 2022 all right reserved,powered by Gitbook该文章修订时间: 2022-06-18 19:33:45

results matching ""

    No results matching ""