Skip to content

Commit 72d732b

Browse files
remychantenayponimas
authored andcommitted
Update approach to passing masked keys
Signed-off-by: Remy Chantenay <[email protected]>
1 parent 9476086 commit 72d732b

File tree

4 files changed

+47
-29
lines changed

4 files changed

+47
-29
lines changed

Diff for: logging/access.go

+28-16
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"fmt"
55
"net"
66
"net/http"
7-
"strconv"
87
"strings"
98
"time"
109

@@ -23,6 +22,10 @@ const (
2322
combinedLogFormat = commonLogFormat + ` "%s" "%s"`
2423
// We add the duration in ms, a requested host and a flow id and audit log
2524
accessLogFormat = combinedLogFormat + " %d %s %s %s\n"
25+
26+
// KeyMaskedQueryParams represents the key used to store and retrieve masked query parameters
27+
// from the additional data.
28+
KeyMaskedQueryParams = "maskedQueryParams"
2629
)
2730

2831
type accessLogFormatter struct {
@@ -111,13 +114,32 @@ func stripQueryString(u string) string {
111114
}
112115
}
113116

117+
// maskQueryParams masks (i.e., hashing) specific query parameters in the provided request's URI.
118+
// Returns the obfuscated URI.
119+
func maskQueryParams(req *http.Request, maskedQueryParams []string) string {
120+
strippedURI := stripQueryString(req.RequestURI)
121+
122+
params := req.URL.Query()
123+
for i := range maskedQueryParams {
124+
val := params.Get(maskedQueryParams[i])
125+
if val == "" {
126+
continue
127+
}
128+
129+
hashed := hash(val)
130+
params.Set(maskedQueryParams[i], fmt.Sprintf("%d", hashed))
131+
}
132+
133+
return fmt.Sprintf("%s?%s", strippedURI, params.Encode())
134+
}
135+
114136
func hash(val string) uint64 {
115137
return xxhash.Sum64String(val)
116138
}
117139

118140
// Logs an access event in Apache combined log format (with a minor customization with the duration).
119141
// Additional allows to provide extra data that may be also logged, depending on the specific log format.
120-
func LogAccess(entry *AccessEntry, additional map[string]interface{}, maskedQueryParams []string) {
142+
func LogAccess(entry *AccessEntry, additional map[string]interface{}) {
121143
if accessLog == nil || entry == nil {
122144
return
123145
}
@@ -150,21 +172,10 @@ func LogAccess(entry *AccessEntry, additional map[string]interface{}, maskedQuer
150172
uri = entry.Request.RequestURI
151173
if stripQuery {
152174
uri = stripQueryString(uri)
153-
} else if len(maskedQueryParams) != 0 {
154-
strippedURI := stripQueryString(uri)
155-
156-
params := entry.Request.URL.Query()
157-
for i := range maskedQueryParams {
158-
val := params.Get(maskedQueryParams[i])
159-
if val == "" {
160-
continue
161-
}
162-
163-
hashed := hash(val)
164-
params.Set(maskedQueryParams[i], strconv.Itoa(int(hashed)))
175+
} else if keys, ok := additional[KeyMaskedQueryParams].([]string); ok {
176+
if len(keys) > 0 {
177+
uri = maskQueryParams(entry.Request, keys)
165178
}
166-
167-
uri = fmt.Sprintf("%s?%s", strippedURI, params.Encode())
168179
}
169180

170181
auditHeader = entry.Request.Header.Get(logFilter.UnverifiedAuditHeader)
@@ -187,6 +198,7 @@ func LogAccess(entry *AccessEntry, additional map[string]interface{}, maskedQuer
187198
"auth-user": authUser,
188199
}
189200

201+
delete(additional, KeyMaskedQueryParams)
190202
for k, v := range additional {
191203
logData[k] = v
192204
}

Diff for: logging/access_test.go

+10-11
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,18 @@ func testAccessEntryWithQueryParameters(params url.Values) *AccessEntry {
8080
}
8181

8282
func testAccessLog(t *testing.T, entry *AccessEntry, expectedOutput string, o Options) {
83-
testAccessLogExtended(t, entry, nil, nil, expectedOutput, o)
83+
testAccessLogExtended(t, entry, nil, expectedOutput, o)
8484
}
8585

8686
func testAccessLogExtended(t *testing.T, entry *AccessEntry,
8787
additional map[string]interface{},
88-
maskedQueryParams []string,
8988
expectedOutput string,
9089
o Options,
9190
) {
9291
var buf bytes.Buffer
9392
o.AccessLogOutput = &buf
9493
Init(o)
95-
LogAccess(entry, additional, maskedQueryParams)
94+
LogAccess(entry, additional)
9695
got := buf.String()
9796
if got != "" {
9897
got = got[:len(got)-1]
@@ -133,18 +132,18 @@ func TestAccessLogFormatJSON(t *testing.T) {
133132
}
134133

135134
func TestAccessLogFormatJSONWithAdditionalData(t *testing.T) {
136-
testAccessLogExtended(t, testAccessEntry(), map[string]interface{}{"extra": "extra"}, nil, logExtendedJSONOutput, Options{AccessLogJSONEnabled: true})
135+
testAccessLogExtended(t, testAccessEntry(), map[string]interface{}{"extra": "extra"}, logExtendedJSONOutput, Options{AccessLogJSONEnabled: true})
137136
}
138137

139138
func TestAccessLogFormatJSONWithMaskedQueryParameters(t *testing.T) {
140-
maskedQueryParams := []string{"key_1"}
139+
additional := map[string]interface{}{KeyMaskedQueryParams: []string{"foo"}}
141140

142141
params := url.Values{}
143-
params.Add("key_1", "value_1")
142+
params.Add("foo", "bar")
144143
testAccessLogExtended(t,
145144
testAccessEntryWithQueryParameters(params),
146-
nil, maskedQueryParams,
147-
`{"audit":"","auth-user":"","duration":42,"flow-id":"","host":"127.0.0.1","level":"info","method":"GET","msg":"","proto":"HTTP/1.1","referer":"","requested-host":"example.com","response-size":2326,"status":418,"timestamp":"10/Oct/2000:13:55:36 -0700","uri":"/apache_pb.gif?key_1=3272669212","user-agent":""}`,
145+
additional,
146+
`{"audit":"","auth-user":"","duration":42,"flow-id":"","host":"127.0.0.1","level":"info","method":"GET","msg":"","proto":"HTTP/1.1","referer":"","requested-host":"example.com","response-size":2326,"status":418,"timestamp":"10/Oct/2000:13:55:36 -0700","uri":"/apache_pb.gif?foo=5234164152756840025","user-agent":""}`,
148147
Options{AccessLogJSONEnabled: true},
149148
)
150149
}
@@ -340,10 +339,10 @@ func TestAccessLogStripQuery(t *testing.T) {
340339
}
341340

342341
func TestHashQueryParamValue(t *testing.T) {
343-
want := "2972666014"
344-
got := hashQueryParamValue("foo")
342+
want := uint64(3728699739546630719)
343+
got := hash("foo")
345344

346345
if got != want {
347-
t.Errorf("\ngot %q\nwant %q", got, want)
346+
t.Errorf("\ngot %v\nwant %v", got, want)
348347
}
349348
}

Diff for: logging/log_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestCustomPrefixForApplicationLog(t *testing.T) {
3838
func TestCustomOutputForAccessLog(t *testing.T) {
3939
var buf bytes.Buffer
4040
Init(Options{AccessLogOutput: &buf})
41-
LogAccess(&AccessEntry{StatusCode: http.StatusTeapot}, nil, nil)
41+
LogAccess(&AccessEntry{StatusCode: http.StatusTeapot}, nil)
4242
if !strings.Contains(buf.String(), strconv.Itoa(http.StatusTeapot)) {
4343
t.Error("failed to use custom access log output")
4444
}

Diff for: proxy/proxy.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -1579,8 +1579,15 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
15791579
}
15801580

15811581
additionalData, _ := ctx.stateBag[al.AccessLogAdditionalDataKey].(map[string]interface{})
1582+
if len(accessLogEnabled.MaskedQueryParams) > 0 {
1583+
if additionalData == nil {
1584+
additionalData = make(map[string]interface{})
1585+
}
1586+
1587+
additionalData[logging.KeyMaskedQueryParams] = accessLogEnabled.MaskedQueryParams
1588+
}
15821589

1583-
logging.LogAccess(entry, additionalData, accessLogEnabled.MaskedQueryParams)
1590+
logging.LogAccess(entry, additionalData)
15841591
}
15851592

15861593
// This flush is required in I/O error

0 commit comments

Comments
 (0)