mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 08:05:43 -06:00
Proxy: Improve header handling for reverse proxy (#67279)
This commit is contained in:
parent
2306fb38dc
commit
cefeef7134
@ -1,6 +1,7 @@
|
||||
package proxyutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
@ -75,6 +76,16 @@ func SetProxyResponseHeaders(header http.Header) {
|
||||
header.Set("Content-Security-Policy", "sandbox")
|
||||
}
|
||||
|
||||
// SetViaHeader adds Grafana's reverse proxy to the proxy chain.
|
||||
// Defined in RFC 9110 7.6.3 https://datatracker.ietf.org/doc/html/rfc9110#name-via
|
||||
func SetViaHeader(header http.Header, major, minor int) {
|
||||
via := fmt.Sprintf("%d.%d grafana", major, minor)
|
||||
if old := header.Get("Via"); old != "" {
|
||||
via = fmt.Sprintf("%s, %s", via, old)
|
||||
}
|
||||
header.Set("Via", via)
|
||||
}
|
||||
|
||||
// ApplyUserHeader Set the X-Grafana-User header if needed (and remove if not).
|
||||
func ApplyUserHeader(sendUserHeader bool, req *http.Request, user *user.SignedInUser) {
|
||||
req.Header.Del(UserHeaderName)
|
||||
|
@ -79,11 +79,30 @@ func wrapDirector(d func(*http.Request)) func(req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// deletedHeaders lists a number of headers that we don't want to
|
||||
// pass-through from the upstream when using a reverse proxy.
|
||||
//
|
||||
// These are related to the connection between Grafana and the proxy
|
||||
// or instructions that would alter how a browser will interact with
|
||||
// future requests to Grafana (such as enabling Strict Transport
|
||||
// Security)
|
||||
var deletedHeaders = []string{
|
||||
"Alt-Svc",
|
||||
"Close",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Strict-Transport-Security",
|
||||
}
|
||||
|
||||
// modifyResponse enforces certain constraints on http.Response.
|
||||
func modifyResponse(logger glog.Logger) func(resp *http.Response) error {
|
||||
return func(resp *http.Response) error {
|
||||
resp.Header.Del("Set-Cookie")
|
||||
for _, header := range deletedHeaders {
|
||||
resp.Header.Del(header)
|
||||
}
|
||||
|
||||
SetProxyResponseHeaders(resp.Header)
|
||||
SetViaHeader(resp.Header, resp.ProtoMajor, resp.ProtoMinor)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ func TestReverseProxy(t *testing.T) {
|
||||
upstream := newUpstreamServer(t, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
actualReq = req
|
||||
http.SetCookie(w, &http.Cookie{Name: "test"})
|
||||
w.Header().Set("Strict-Transport-Security", "max-age=31536000")
|
||||
w.Header().Set("X-Custom-Hdr", "Ok!")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
t.Cleanup(upstream.Close)
|
||||
@ -52,11 +54,14 @@ func TestReverseProxy(t *testing.T) {
|
||||
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"))
|
||||
require.Empty(t, actualReq.Header.Get("Authorization"))
|
||||
resp := rec.Result()
|
||||
require.Empty(t, resp.Cookies())
|
||||
require.Equal(t, "sandbox", resp.Header.Get("Content-Security-Policy"))
|
||||
require.Contains(t, resp.Header, "X-Custom-Hdr")
|
||||
require.NotContains(t, resp.Header, "Strict-Transport-Security")
|
||||
require.Contains(t, resp.Header.Get("Via"), "grafana")
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Empty(t, actualReq.Header.Get("Authorization"))
|
||||
})
|
||||
|
||||
t.Run("When proxying a request using WithModifyResponse should call it before default ModifyResponse func", func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user