Skip to content

Commit 91f6f4a

Browse files
chore: redact api-key headers in debug logs
1 parent 8032ad8 commit 91f6f4a

1 file changed

Lines changed: 44 additions & 2 deletions

File tree

option/middleware.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import (
88
"net/http/httputil"
99
)
1010

11+
// sensitiveLogHeaders are redacted before request and response content is
12+
// written to the debug logger.
13+
var sensitiveLogHeaders = []string{"authorization", "api-key", "x-api-key", "cookie", "set-cookie"}
14+
1115
// WithDebugLog logs the HTTP request and response content.
1216
// If the logger parameter is nil, it uses the default logger.
1317
//
@@ -20,7 +24,7 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2024
logger = log.Default()
2125
}
2226

23-
if reqBytes, err := httputil.DumpRequest(req, true); err == nil {
27+
if reqBytes, err := dumpRedactedRequest(req); err == nil {
2428
logger.Printf("Request Content:\n%s\n", reqBytes)
2529
}
2630

@@ -29,10 +33,48 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2933
return resp, err
3034
}
3135

32-
if respBytes, err := httputil.DumpResponse(resp, true); err == nil {
36+
if respBytes, err := dumpRedactedResponse(resp); err == nil {
3337
logger.Printf("Response Content:\n%s\n", respBytes)
3438
}
3539

3640
return resp, err
3741
})
3842
}
43+
44+
// dumpRedactedRequest dumps req with sensitive headers replaced. The
45+
// original headers are restored via defer so a panic in DumpRequest cannot
46+
// leak the placeholder map into the live request sent downstream.
47+
func dumpRedactedRequest(req *http.Request) ([]byte, error) {
48+
origHeaders := req.Header
49+
req.Header = redactDebugHeaders(origHeaders)
50+
defer func() { req.Header = origHeaders }()
51+
return httputil.DumpRequest(req, true)
52+
}
53+
54+
func dumpRedactedResponse(resp *http.Response) ([]byte, error) {
55+
origHeaders := resp.Header
56+
resp.Header = redactDebugHeaders(origHeaders)
57+
defer func() { resp.Header = origHeaders }()
58+
return httputil.DumpResponse(resp, true)
59+
}
60+
61+
func redactDebugHeaders(headers http.Header) http.Header {
62+
var redacted http.Header
63+
for _, name := range sensitiveLogHeaders {
64+
values := headers.Values(name)
65+
if len(values) == 0 {
66+
continue
67+
}
68+
if redacted == nil {
69+
redacted = headers.Clone()
70+
}
71+
redacted.Del(name)
72+
for range values {
73+
redacted.Add(name, "***")
74+
}
75+
}
76+
if redacted == nil {
77+
return headers
78+
}
79+
return redacted
80+
}

0 commit comments

Comments
 (0)