Sky's自留地

关注互联网安全,关注安全&攻击技术。

Resty 记录request&response

技术类 阅读: 2391 0 评

问题

因为目前写的工具中,采用了Resty作为http 客户端,在调试插件的过程中,需要将request包以及response保存并且打印出来,方便后续对攻击请求的包进行分析。
Resty内部有一个方法简单看了下,应该是可以满足此需求的,方法名为,存在与

/github.com/go-resty/resty/v2@v2.3.0/client.go:898 outputLogTo ()

实现

但是由于是内部方法,根本无法调用,所以采取了自定义RoundTripper的方式对请求的发送包以及响应包进行记录,简易代码如下:

/*
Copyright © 2020 sky sky@03sec.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
    "crypto/tls"
    "encoding/base64"
    "fmt"
    "github.com/go-resty/resty/v2"
    "net/http"
    "net/http/httputil"
    "strings"
    "sync"
    "time"
)
func main() {
    var m sync.Map
    r, err := resty.New().
        SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
        SetTimeout(15 * time.Second).
        SetTransport(newRoundTripper(&m, nil)).
        SetRedirectPolicy(resty.FlexibleRedirectPolicy(0)).
        R().Get("http://03sec.com")
    if err != nil && !strings.Contains(err.Error(), "stopped after ") {
        fmt.Println(err)
    }
    reqMap, reqStatus := m.Load(r.RawResponse.Request.URL.String() + "_REQ")
    if reqStatus {
        ReqStr, _ := base64.StdEncoding.DecodeString(reqMap.(string))
        fmt.Println(string(ReqStr))
    }
    respMap, respStatus := m.Load(r.RawResponse.Request.URL.String() + "_RESP")
    if respStatus {
        RespStr, _ := base64.StdEncoding.DecodeString(respMap.(string))
        fmt.Println(string(RespStr))
    }
}
// NewRoundTripper returns new RoundTripper instance for logging http request and response
func newRoundTripper(m *sync.Map, parent http.RoundTripper) http.RoundTripper {
    return &rrLogTransport{
        writer: m,
        parent: parent,
    }
}
type rrLogTransport struct {
    writer *sync.Map
    parent http.RoundTripper
}
func (lt *rrLogTransport) parentTransport() http.RoundTripper {
    if lt.parent == nil {
        return http.DefaultTransport
    }
    return lt.parent
}
func (lt *rrLogTransport) CancelRequest(req *http.Request) {
    type canceler interface {
        CancelRequest(*http.Request)
    }
    if cr, ok := lt.parentTransport().(canceler); ok {
        cr.CancelRequest(req)
    }
}
func (lt *rrLogTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    reqDump, _ := httputil.DumpRequest(req, true)
    lt.writer.Store(req.URL.String()+"_REQ", base64.StdEncoding.EncodeToString(reqDump))
    resp, _ := lt.parentTransport().RoundTrip(req)
    respDump, err := httputil.DumpResponse(resp, true)
    lt.writer.Store(req.URL.String()+"_RESP", base64.StdEncoding.EncodeToString(respDump))
    return resp, err
}

其主要核心就是RoundTrip方法,在这其中,使用httputil包下的DumpRequest方法以及DumpResponse对请求和响应进行了记录,并且使用了其当前的URL地址作为Key进行保存,在后续需要的时候使用URL将其取出来即可。

WappalyzerParse Golang 解析库
发表评论
撰写评论