Skip to content

Commit

Permalink
Send sanitized list of HTTP request query params to the host agent
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Slotin committed Aug 12, 2020
1 parent 3a6b3b9 commit 96d6217
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 5 deletions.
26 changes: 26 additions & 0 deletions instrumentation_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ func TracingHandlerFunc(sensor *Sensor, pathTemplate string, handler http.Handle
span := tracer.StartSpan("g.http", opts...)
defer span.Finish()

if t, ok := tracer.(Tracer); ok {
params := collectHTTPParams(req, t.Options().Secrets)
if len(params) > 0 {
span.SetTag("http.params", params.Encode())
}
}

defer func() {
// Be sure to capture any kind of panic / error
if err := recover(); err != nil {
Expand Down Expand Up @@ -129,6 +136,13 @@ func RoundTripper(sensor *Sensor, original http.RoundTripper) http.RoundTripper
req = cloneRequest(ContextWithSpan(ctx, span), req)
sensor.Tracer().Inject(span.Context(), ot.HTTPHeaders, ot.HTTPHeadersCarrier(req.Header))

if t, ok := sensor.Tracer().(Tracer); ok {
params := collectHTTPParams(req, t.Options().Secrets)
if len(params) > 0 {
span.SetTag("http.params", params.Encode())
}
}

resp, err := original.RoundTrip(req)
if err != nil {
span.SetTag("http.error", err.Error())
Expand Down Expand Up @@ -167,6 +181,18 @@ func (rt tracingRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
return rt(req)
}

func collectHTTPParams(req *http.Request, matcher Matcher) url.Values {
params := cloneURLValues(req.URL.Query())

for k := range params {
if matcher.Match(k) {
params[k] = []string{"<redacted>"}
}
}

return params
}

// The following code is ported from $GOROOT/src/net/http/clone.go with minor changes
// for compatibility with Go versions prior to 1.13
//
Expand Down
62 changes: 57 additions & 5 deletions instrumentation_http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestTracingHandlerFunc_Write(t *testing.T) {
fmt.Fprintln(w, "Ok")
})

req := httptest.NewRequest(http.MethodGet, "/test?q=classified", nil)
req := httptest.NewRequest(http.MethodGet, "/test?q=term", nil)

rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
Expand Down Expand Up @@ -52,6 +52,7 @@ func TestTracingHandlerFunc_Write(t *testing.T) {
Status: http.StatusOK,
Method: "GET",
Path: "/test",
Params: "q=term",
PathTemplate: "/{action}",
}, data.Tags)

Expand All @@ -69,7 +70,7 @@ func TestTracingHandlerFunc_WriteHeaders(t *testing.T) {
})

rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/test?q=classified", nil))
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/test?q=term", nil))

assert.Equal(t, http.StatusNotFound, rec.Code)

Expand All @@ -89,9 +90,57 @@ func TestTracingHandlerFunc_WriteHeaders(t *testing.T) {
Method: "GET",
Host: "example.com",
Path: "/test",
Params: "q=term",
}, data.Tags)
}

func TestTracingHandlerFunc_SecretsFiltering(t *testing.T) {
recorder := instana.NewTestRecorder()
s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{
Service: "go-sensor-test",
}, recorder))

h := instana.TracingHandlerFunc(s, "/{action}", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Ok")
})

req := httptest.NewRequest(http.MethodGet, "/test?q=term&sensitive_key=s3cr3t&myPassword=qwerty&SECRET_VALUE=1", nil)

rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)

assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "Ok\n", rec.Body.String())

spans := recorder.GetQueuedSpans()
require.Len(t, spans, 1)

span := spans[0]
assert.Equal(t, 0, span.Ec)
assert.EqualValues(t, instana.EntrySpanKind, span.Kind)
assert.False(t, span.Synthetic)
assert.Empty(t, span.CorrelationType)
assert.Empty(t, span.CorrelationID)

assert.Nil(t, span.ForeignParent)

require.IsType(t, instana.HTTPSpanData{}, span.Data)
data := span.Data.(instana.HTTPSpanData)

assert.Equal(t, instana.HTTPSpanTags{
Host: "example.com",
Status: http.StatusOK,
Method: "GET",
Path: "/test",
Params: "SECRET_VALUE=%3Credacted%3E&myPassword=%3Credacted%3E&q=term&sensitive_key=%3Credacted%3E",
PathTemplate: "/{action}",
}, data.Tags)

// check whether the trace context has been sent back to the client
assert.Equal(t, instana.FormatID(span.TraceID), rec.Header().Get(instana.FieldT))
assert.Equal(t, instana.FormatID(span.SpanID), rec.Header().Get(instana.FieldS))
}

func TestTracingHandlerFunc_Error(t *testing.T) {
recorder := instana.NewTestRecorder()
s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{}, recorder))
Expand Down Expand Up @@ -249,7 +298,7 @@ func TestTracingHandlerFunc_PanicHandling(t *testing.T) {

rec := httptest.NewRecorder()
assert.Panics(t, func() {
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/test?q=classified", nil))
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/test?q=term", nil))
})

spans := recorder.GetQueuedSpans()
Expand All @@ -268,6 +317,7 @@ func TestTracingHandlerFunc_PanicHandling(t *testing.T) {
Method: "GET",
Host: "example.com",
Path: "/test",
Params: "q=term",
Error: "something went wrong",
}, data.Tags)
}
Expand All @@ -291,7 +341,7 @@ func TestRoundTripper(t *testing.T) {
}))

ctx := instana.ContextWithSpan(context.Background(), parentSpan)
req := httptest.NewRequest("GET", "http://user:[email protected]/hello", nil)
req := httptest.NewRequest("GET", "http://user:[email protected]/hello?q=term&sensitive_key=s3cr3t&myPassword=qwerty&SECRET_VALUE=1", nil)

_, err := rt.RoundTrip(req.WithContext(ctx))
require.NoError(t, err)
Expand All @@ -318,6 +368,7 @@ func TestRoundTripper(t *testing.T) {
Method: "GET",
Status: http.StatusNotImplemented,
URL: "http://example.com/hello",
Params: "SECRET_VALUE=%3Credacted%3E&myPassword=%3Credacted%3E&q=term&sensitive_key=%3Credacted%3E",
}, data.Tags)
}

Expand Down Expand Up @@ -353,7 +404,7 @@ func TestRoundTripper_Error(t *testing.T) {
}))

ctx := instana.ContextWithSpan(context.Background(), s.Tracer().StartSpan("parent"))
req := httptest.NewRequest("GET", "http://example.com/hello", nil)
req := httptest.NewRequest("GET", "http://example.com/hello?q=term&key=s3cr3t", nil)

_, err := rt.RoundTrip(req.WithContext(ctx))
assert.Error(t, err)
Expand All @@ -371,6 +422,7 @@ func TestRoundTripper_Error(t *testing.T) {
assert.Equal(t, instana.HTTPSpanTags{
Method: "GET",
URL: "http://example.com/hello",
Params: "key=%3Credacted%3E&q=term",
Error: "something went wrong",
}, data.Tags)
}
Expand Down

0 comments on commit 96d6217

Please sign in to comment.