Skip to content

Commit

Permalink
fix: sanitize X-Forwarded-Proto header in RedirectScheme middleware
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Salleyron <[email protected]>
  • Loading branch information
ldez and juliens authored Dec 16, 2022
1 parent e7baf44 commit 29b8b69
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
25 changes: 20 additions & 5 deletions pkg/middlewares/redirect/redirect_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ const (
xForwardedProto = "X-Forwarded-Proto"
)

type redirectScheme struct {
http.Handler

name string
}

// NewRedirectScheme creates a new RedirectScheme middleware.
func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.RedirectScheme, name string) (http.Handler, error) {
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeSchemeName))
Expand All @@ -33,10 +39,19 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
port = ":" + conf.Port
}

return newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, clientRequestURL, name)
rs := &redirectScheme{name: name}

handler, err := newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, rs.clientRequestURL, name)
if err != nil {
return nil, err
}

rs.Handler = handler

return rs, nil
}

func clientRequestURL(req *http.Request) string {
func (r *redirectScheme) clientRequestURL(req *http.Request) string {
scheme := schemeHTTP
host, port, err := net.SplitHostPort(req.Host)
if err != nil {
Expand Down Expand Up @@ -71,12 +86,12 @@ func clientRequestURL(req *http.Request) string {
// Given that we're in a middleware that is only used in the context of HTTP(s) requests,
// the only possible valid schemes are one of "http" or "https", so we convert back to them.
switch {
case strings.EqualFold(xProto, "ws"):
case strings.EqualFold(xProto, schemeHTTP), strings.EqualFold(xProto, "ws"):
scheme = schemeHTTP
case strings.EqualFold(xProto, "wss"):
case strings.EqualFold(xProto, schemeHTTPS), strings.EqualFold(xProto, "wss"):
scheme = schemeHTTPS
default:
scheme = xProto
log.FromContext(middlewares.GetLoggerCtx(req.Context(), r.name, typeSchemeName)).Debugf("invalid X-Forwarded-Proto: %s", xProto)
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/middlewares/redirect/redirect_scheme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
headers: map[string]string{
"X-Forwarded-Proto": "bar",
},
expectedURL: "https://bar://foo",
expectedURL: "https://foo",
expectedStatus: http.StatusFound,
},
{
Expand Down

0 comments on commit 29b8b69

Please sign in to comment.