diff --git a/client.go b/client.go index 35e7b16..1f793d4 100644 --- a/client.go +++ b/client.go @@ -910,16 +910,16 @@ func (c *Client) StandardClient() *http.Client { } } -// Taken from url.URL#Redacted() which was introduced in go 1.15. -// We can switch to using it directly if we'll bump the minimum required go version. +// Should be aligned with wiz-sec/wiz/commonlib/anonymize/anonymize.go#RedactURL() func redactURL(u *url.URL) string { if u == nil { return "" } ru := *u - if _, has := ru.User.Password(); has { - ru.User = url.UserPassword(ru.User.Username(), "xxxxx") - } - return ru.String() + + // Remove query as it might contain secrets, e.g. presigned URLs + ru.RawQuery = "" + ru.ForceQuery = false + return ru.Redacted() } diff --git a/client_test.go b/client_test.go index 1975221..0b4abe2 100644 --- a/client_test.go +++ b/client_test.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "log" "net" "net/http" "net/http/httptest" @@ -1283,3 +1284,37 @@ func TestClient_RedirectWithBody(t *testing.T) { t.Fatalf("Expected the client to be redirected 2 times, got: %d", atomic.LoadInt32(&redirects)) } } + +func TestUrlQueryParamsAreRedactedFromLogs(t *testing.T) { + ts := serveFailOnceServer() + defer ts.Close() + + logBuffer := &bytes.Buffer{} + logger := log.New(logBuffer, "", log.LstdFlags) + client := NewClient() + client.Logger = logger + + resp, err := client.Get(ts.URL + "?X-Amz-Credential=SECRET") + if err != nil { + t.Fatalf("err: %v", err) + } + resp.Body.Close() + + actualLogs := string(logBuffer.Bytes()) + if strings.Contains(actualLogs, "SECRET") { + t.Fatalf("log contains SECRET that should have been redacted: %s", actualLogs) + } +} + +func serveFailOnceServer() *httptest.Server { + var retries int32 = 0 + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if atomic.LoadInt32(&retries) == 0 { + w.WriteHeader(500) + } else { + w.WriteHeader(200) + } + + atomic.AddInt32(&retries, 1) + })) +}