From b0874d80593aaf48038653bb5d462fa585d92fde Mon Sep 17 00:00:00 2001 From: Neil Fordyce Date: Thu, 15 Dec 2022 09:08:10 +0000 Subject: [PATCH] DataProxy: Populate X-Grafana-Referer header (#60040) * ProxyUtil: Populate X-Grafana-Referer header * ProxyUtil: Move Referer/Origin header removal So that the removal and setting X-Grafana-Referer logic applies to all proxied requests and not just datasource proxy. * ProxyUtil: Test to guard against multiline headers * ProxyUtil: Explicitly check injected header isn't parsed --- pkg/util/proxyutil/proxyutil.go | 10 +++++++- pkg/util/proxyutil/proxyutil_test.go | 32 ++++++++++++++++++++++++ pkg/util/proxyutil/reverse_proxy.go | 4 --- pkg/util/proxyutil/reverse_proxy_test.go | 1 + 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/pkg/util/proxyutil/proxyutil.go b/pkg/util/proxyutil/proxyutil.go index ee56120cc6f..50897634838 100644 --- a/pkg/util/proxyutil/proxyutil.go +++ b/pkg/util/proxyutil/proxyutil.go @@ -7,9 +7,17 @@ import ( ) // PrepareProxyRequest prepares a request for being proxied. -// Removes X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto headers. +// Removes X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, Origin, Referer headers. +// Set X-Grafana-Referer based on contents of Referer. // Set X-Forwarded-For headers. func PrepareProxyRequest(req *http.Request) { + // Set X-Grafana-Referer to correlate access logs to dashboards + req.Header.Set("X-Grafana-Referer", req.Header.Get("Referer")) + + // Clear Origin and Referer to avoid CORS issues + req.Header.Del("Origin") + req.Header.Del("Referer") + req.Header.Del("X-Forwarded-Host") req.Header.Del("X-Forwarded-Port") req.Header.Del("X-Forwarded-Proto") diff --git a/pkg/util/proxyutil/proxyutil_test.go b/pkg/util/proxyutil/proxyutil_test.go index 03d816bbcd8..209c7a01fac 100644 --- a/pkg/util/proxyutil/proxyutil_test.go +++ b/pkg/util/proxyutil/proxyutil_test.go @@ -8,6 +8,38 @@ import ( ) func TestPrepareProxyRequest(t *testing.T) { + t.Run("Prepare proxy request should clear Origin and Referer headers", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, "/", nil) + require.NoError(t, err) + req.Header.Set("Origin", "https://host.com") + req.Header.Set("Referer", "https://host.com/dashboard") + + PrepareProxyRequest(req) + require.NotContains(t, req.Header, "Origin") + require.NotContains(t, req.Header, "Referer") + }) + + t.Run("Prepare proxy request should set X-Grafana-Referer header", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, "/", nil) + require.NoError(t, err) + req.Header.Set("Referer", "https://host.com/dashboard") + + PrepareProxyRequest(req) + require.Contains(t, req.Header, "X-Grafana-Referer") + require.Equal(t, "https://host.com/dashboard", req.Header.Get("X-Grafana-Referer")) + }) + + t.Run("Prepare proxy request X-Grafana-Referer handles multiline", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, "/", nil) + require.NoError(t, err) + req.Header.Set("Referer", "https://www.google.ch\r\nOtherHeader:https://www.somethingelse.com") + + PrepareProxyRequest(req) + require.Contains(t, req.Header, "X-Grafana-Referer") + require.NotContains(t, req.Header, "OtherHeader") + require.Equal(t, "https://www.google.ch\r\nOtherHeader:https://www.somethingelse.com", req.Header.Get("X-Grafana-Referer")) + }) + t.Run("Prepare proxy request should clear X-Forwarded headers", func(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/", nil) require.NoError(t, err) diff --git a/pkg/util/proxyutil/reverse_proxy.go b/pkg/util/proxyutil/reverse_proxy.go index bff95092298..668015edf15 100644 --- a/pkg/util/proxyutil/reverse_proxy.go +++ b/pkg/util/proxyutil/reverse_proxy.go @@ -76,10 +76,6 @@ func wrapDirector(d func(*http.Request)) func(req *http.Request) { d(req) PrepareProxyRequest(req) - - // Clear Origin and Referer to avoid CORS issues - req.Header.Del("Origin") - req.Header.Del("Referer") } } diff --git a/pkg/util/proxyutil/reverse_proxy_test.go b/pkg/util/proxyutil/reverse_proxy_test.go index b5dfee0c3e9..6d3376a421f 100644 --- a/pkg/util/proxyutil/reverse_proxy_test.go +++ b/pkg/util/proxyutil/reverse_proxy_test.go @@ -50,6 +50,7 @@ func TestReverseProxy(t *testing.T) { require.Equal(t, "10.0.0.1", actualReq.Header.Get("X-Forwarded-For")) require.Empty(t, actualReq.Header.Get("Origin")) require.Empty(t, actualReq.Header.Get("Referer")) + require.Equal(t, "https://test.com/api", actualReq.Header.Get("X-Grafana-Referer")) require.Equal(t, "value", actualReq.Header.Get("X-KEY")) resp := rec.Result() require.Empty(t, resp.Cookies())