From 8a6743438077a6d089260c12adf3da5eca59fb3a Mon Sep 17 00:00:00 2001 From: Timo Reimann Date: Thu, 5 Oct 2017 12:14:03 +0200 Subject: [PATCH] Sanitize cookie names. --- server/server.go | 28 +++++++++++++++++++++++++++- server/server_test.go | 7 +++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index e13dff8fd..370c5c79d 100644 --- a/server/server.go +++ b/server/server.go @@ -15,6 +15,7 @@ import ( "reflect" "regexp" "sort" + "strings" "sync" "time" @@ -826,7 +827,7 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf } stickySession := config.Backends[frontend.Backend].LoadBalancer.Sticky - cookieName := "_TRAEFIK_BACKEND_" + frontend.Backend + cookieName := getCookieName(frontend.Backend) var sticky *roundrobin.StickySession if stickySession { @@ -1208,3 +1209,28 @@ func (server *Server) buildRetryMiddleware(handler http.Handler, globalConfig co return middlewares.NewRetry(retryAttempts, handler, retryListeners) } + +// getCookieName returns a cookie name from the given backend, sanitizing +// characters that do not satisfy the requirements of RFC 2616. +func getCookieName(backend string) string { + const cookiePrefix = "_TRAEFIK_BACKEND_" + sanitizer := func(r rune) rune { + switch r { + case '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '`', '|', '~': + return r + } + + switch { + case r >= 'a' && r <= 'z': + fallthrough + case r >= 'A' && r <= 'Z': + fallthrough + case r >= '0' && r <= '9': + return r + default: + return '_' + } + } + + return cookiePrefix + strings.Map(sanitizer, backend) +} diff --git a/server/server_test.go b/server/server_test.go index a1575fddb..bbac7b5d2 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -659,6 +659,13 @@ func TestServerResponseEmptyBackend(t *testing.T) { } } +func TestGetCookieName(t *testing.T) { + want := "_TRAEFIK_BACKEND__my_BACKEND-v1.0~rc1" + if got := getCookieName("/my/BACKEND-v1.0~rc1"); got != want { + t.Errorf("got sticky cookie name %q, want %q", got, want) + } +} + func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration { config := &types.Configuration{ Frontends: make(map[string]*types.Frontend),