fix: sanitize X-Forwarded-Proto header in RedirectScheme middleware
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
parent
e7baf44a2e
commit
29b8b6911e
2 changed files with 21 additions and 6 deletions
|
@ -18,6 +18,12 @@ const (
|
||||||
xForwardedProto = "X-Forwarded-Proto"
|
xForwardedProto = "X-Forwarded-Proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type redirectScheme struct {
|
||||||
|
http.Handler
|
||||||
|
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
// NewRedirectScheme creates a new RedirectScheme middleware.
|
// NewRedirectScheme creates a new RedirectScheme middleware.
|
||||||
func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.RedirectScheme, name string) (http.Handler, error) {
|
func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.RedirectScheme, name string) (http.Handler, error) {
|
||||||
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeSchemeName))
|
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeSchemeName))
|
||||||
|
@ -33,10 +39,19 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
|
||||||
port = ":" + conf.Port
|
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
|
scheme := schemeHTTP
|
||||||
host, port, err := net.SplitHostPort(req.Host)
|
host, port, err := net.SplitHostPort(req.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -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,
|
// 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.
|
// the only possible valid schemes are one of "http" or "https", so we convert back to them.
|
||||||
switch {
|
switch {
|
||||||
case strings.EqualFold(xProto, "ws"):
|
case strings.EqualFold(xProto, schemeHTTP), strings.EqualFold(xProto, "ws"):
|
||||||
scheme = schemeHTTP
|
scheme = schemeHTTP
|
||||||
case strings.EqualFold(xProto, "wss"):
|
case strings.EqualFold(xProto, schemeHTTPS), strings.EqualFold(xProto, "wss"):
|
||||||
scheme = schemeHTTPS
|
scheme = schemeHTTPS
|
||||||
default:
|
default:
|
||||||
scheme = xProto
|
log.FromContext(middlewares.GetLoggerCtx(req.Context(), r.name, typeSchemeName)).Debugf("invalid X-Forwarded-Proto: %s", xProto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
|
||||||
headers: map[string]string{
|
headers: map[string]string{
|
||||||
"X-Forwarded-Proto": "bar",
|
"X-Forwarded-Proto": "bar",
|
||||||
},
|
},
|
||||||
expectedURL: "https://bar://foo",
|
expectedURL: "https://foo",
|
||||||
expectedStatus: http.StatusFound,
|
expectedStatus: http.StatusFound,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue