From 32e655be524fb036bf4b261566df15c31f59c021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Pitucha?= Date: Fri, 1 May 2020 14:17:38 +1000 Subject: [PATCH 1/4] Support injecting metadata as new field This allows services to add some data which can be correlated with a specific request without trying to match specific time/url/... by hand in the logs. Any string assigned to first `metadata` parameter will be copied verbatim to the logged `metadata` field. --- csp_collector.go | 7 +++++++ csp_collector_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/csp_collector.go b/csp_collector.go index 005a28a..dc92cc8 100644 --- a/csp_collector.go +++ b/csp_collector.go @@ -191,6 +191,12 @@ func handleViolationReport(w http.ResponseWriter, r *http.Request) { return } + metadatas, got_metadata := r.URL.Query()["metadata"] + var metadata string + if got_metadata { + metadata = metadatas[0] + } + log.WithFields(log.Fields{ "document_uri": report.Body.DocumentURI, "referrer": report.Body.Referrer, @@ -201,6 +207,7 @@ func handleViolationReport(w http.ResponseWriter, r *http.Request) { "disposition": report.Body.Disposition, "script_sample": report.Body.ScriptSample, "status_code": report.Body.StatusCode, + "metadata": metadata, }).Info() } diff --git a/csp_collector_test.go b/csp_collector_test.go index e097090..eb11593 100644 --- a/csp_collector_test.go +++ b/csp_collector_test.go @@ -55,6 +55,39 @@ func TestHandlerForAllowingHealthcheck(t *testing.T) { } } +func TestHandlerWithMetadata(t *testing.T) { + var logBuffer bytes.Buffer + log.SetOutput(&logBuffer) + + csp := CSPReport{ + CSPReportBody{ + DocumentURI: "http://example.com", + BlockedURI: "http://example.com", + }, + } + + payload, err := json.Marshal(csp) + + request, err := http.NewRequest("POST", "/?metadata=value", bytes.NewBuffer(payload)) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + recorder := httptest.NewRecorder() + + handleViolationReport(recorder, request) + + response := recorder.Result() + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + t.Errorf("expected HTTP status %v; got %v", http.StatusOK, response.StatusCode) + } + + if !strings.Contains(logBuffer.String(), "metadata=value") { + t.Fatalf("Logged result doesn't contain metadata") + } +} + func TestValidateViolationWithInvalidBlockedURIs(t *testing.T) { invalidBlockedURIs := []string{ "resource://", From 668fda04a1ecdde8aef943de9da3c320f5341580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Pitucha?= Date: Fri, 1 May 2020 15:08:23 +1000 Subject: [PATCH 2/4] Check for first parameter only --- csp_collector_test.go | 45 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/csp_collector_test.go b/csp_collector_test.go index eb11593..c9116a6 100644 --- a/csp_collector_test.go +++ b/csp_collector_test.go @@ -56,9 +56,6 @@ func TestHandlerForAllowingHealthcheck(t *testing.T) { } func TestHandlerWithMetadata(t *testing.T) { - var logBuffer bytes.Buffer - log.SetOutput(&logBuffer) - csp := CSPReport{ CSPReportBody{ DocumentURI: "http://example.com", @@ -66,25 +63,39 @@ func TestHandlerWithMetadata(t *testing.T) { }, } - payload, err := json.Marshal(csp) + payload, _ := json.Marshal(csp) - request, err := http.NewRequest("POST", "/?metadata=value", bytes.NewBuffer(payload)) - if err != nil { - t.Fatalf("failed to create request: %v", err) - } - recorder := httptest.NewRecorder() + for _, repeats := range []int{1, 2} { + var logBuffer bytes.Buffer + log.SetOutput(&logBuffer) - handleViolationReport(recorder, request) + url := "/?" + for i := 0; i < repeats; i += 1 { + url += fmt.Sprintf("metadata=value%d&", i) + } - response := recorder.Result() - defer response.Body.Close() + request, err := http.NewRequest("POST", url, bytes.NewBuffer(payload)) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + recorder := httptest.NewRecorder() - if response.StatusCode != http.StatusOK { - t.Errorf("expected HTTP status %v; got %v", http.StatusOK, response.StatusCode) - } + handleViolationReport(recorder, request) + + response := recorder.Result() + defer response.Body.Close() - if !strings.Contains(logBuffer.String(), "metadata=value") { - t.Fatalf("Logged result doesn't contain metadata") + if response.StatusCode != http.StatusOK { + t.Errorf("expected HTTP status %v; got %v", http.StatusOK, response.StatusCode) + } + + log := logBuffer.String() + if !strings.Contains(log, "metadata=value0") { + t.Fatalf("Logged result should contain metadata value0 in '%s'", log) + } + if strings.Contains(log, "metadata=value1") { + t.Fatalf("Logged result shouldn't contain metadata value1 in '%s'", log) + } } } From bf12606d7ed2f11940892a2618e98ec7ce857b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Pitucha?= Date: Fri, 1 May 2020 15:12:10 +1000 Subject: [PATCH 3/4] Satisfy the linter --- csp_collector.go | 4 ++-- csp_collector_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csp_collector.go b/csp_collector.go index dc92cc8..ef593df 100644 --- a/csp_collector.go +++ b/csp_collector.go @@ -191,9 +191,9 @@ func handleViolationReport(w http.ResponseWriter, r *http.Request) { return } - metadatas, got_metadata := r.URL.Query()["metadata"] + metadatas, gotMetadata := r.URL.Query()["metadata"] var metadata string - if got_metadata { + if gotMetadata { metadata = metadatas[0] } diff --git a/csp_collector_test.go b/csp_collector_test.go index c9116a6..9617ed5 100644 --- a/csp_collector_test.go +++ b/csp_collector_test.go @@ -70,7 +70,7 @@ func TestHandlerWithMetadata(t *testing.T) { log.SetOutput(&logBuffer) url := "/?" - for i := 0; i < repeats; i += 1 { + for i := 0; i < repeats; i++ { url += fmt.Sprintf("metadata=value%d&", i) } From 5d3c61010d0995bfe6c27dd360fe196578c76e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Pitucha?= Date: Fri, 1 May 2020 15:16:31 +1000 Subject: [PATCH 4/4] Add metadata description to README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index f95369a..f36ab89 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,15 @@ $ CGO_ENABLED=0 go build csp_collector.go See the sample.filterlist.txt file as an example of the filter list in a file +### Request metadata + +Additional information can be attached to each report by adding a `metadata` +url parameter to each report. That value will be copied verbatim into the +logged report. + +For example a report sent to `https://collector.example.com/?metadata=foobar` +will include field `metadata` with value `foobar`. + ### Output formats The output format can be controlled by passing `--output-format `