Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: host header should not be allowed to modify #5533

Merged
merged 2 commits into from
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 77 additions & 96 deletions internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,28 +453,19 @@
for _, addHeader := range headersToAdd {
emptyFilterConfig = false
if addHeader.Name == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"RequestHeaderModifier Filter cannot add a header with an empty name",
)
// try to process the rest of the headers and produce a valid config.
continue
}
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
if strings.Contains(string(addHeader.Name), "/") || strings.Contains(string(addHeader.Name), ":") {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
fmt.Sprintf("RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: %q", string(addHeader.Name)),
if !isModifiableHeader(string(addHeader.Name)) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf(
"RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
string(addHeader.Name)),
)
continue
}
Expand Down Expand Up @@ -510,27 +501,19 @@
for _, setHeader := range headersToSet {

if setHeader.Name == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"RequestHeaderModifier Filter cannot set a header with an empty name",
)
continue
}
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
if strings.Contains(string(setHeader.Name), "/") || strings.Contains(string(setHeader.Name), ":") {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
fmt.Sprintf("RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: '%s'", string(setHeader.Name)),

if !isModifiableHeader(string(setHeader.Name)) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf(
"RequestHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
string(setHeader.Name)),
)
continue
}
Expand Down Expand Up @@ -566,18 +549,23 @@
}
for _, removedHeader := range headersToRemove {
if removedHeader == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,

Check warning on line 553 in internal/gatewayapi/filters.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/filters.go#L552-L553

Added lines #L552 - L553 were not covered by tests
"RequestHeaderModifier Filter cannot remove a header with an empty name",
)
continue
}

if !isModifiableHeader(removedHeader) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf(
"RequestHeaderModifier Filter cannot remove headers with a '/' or ':' character in them, or the host header. Header: %q",
removedHeader),
)
continue
}

canRemHeader := true
for _, h := range filterContext.RemoveRequestHeaders {
if strings.EqualFold(h, removedHeader) {
Expand All @@ -595,18 +583,31 @@

// Update the status if the filter failed to configure any valid headers to add/remove
if len(filterContext.AddRequestHeaders) == 0 && len(filterContext.RemoveRequestHeaders) == 0 && !emptyFilterConfig {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"RequestHeaderModifier Filter did not provide valid configuration to add/set/remove any headers",
)
}
}

func updateRouteStatusForRHMFilter(filterContext *HTTPFiltersContext, message string) {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
message,
)
}

func isModifiableHeader(headerName string) bool {
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
// And Envoy does not allow modification the pseudo headers and the host header
return !strings.Contains(headerName, "/") && !strings.Contains(headerName, ":") && !strings.EqualFold(headerName, "host")
}

func (t *Translator) processResponseHeaderModifierFilter(
headerModifier *gwapiv1.HTTPHeaderFilter,
filterContext *HTTPFiltersContext,
Expand All @@ -625,28 +626,18 @@
for _, addHeader := range headersToAdd {
emptyFilterConfig = false
if addHeader.Name == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"ResponseHeaderModifier Filter cannot add a header with an empty name",
)
// try to process the rest of the headers and produce a valid config.
continue
}
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
if strings.Contains(string(addHeader.Name), "/") || strings.Contains(string(addHeader.Name), ":") {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: %q", string(addHeader.Name)),
if !isModifiableHeader(string(addHeader.Name)) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
string(addHeader.Name)),
)
continue
}
Expand Down Expand Up @@ -682,27 +673,18 @@
for _, setHeader := range headersToSet {

if setHeader.Name == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"ResponseHeaderModifier Filter cannot set a header with an empty name",
)
continue
}
// Per Gateway API specification on HTTPHeaderName, : and / are invalid characters in header names
if strings.Contains(string(setHeader.Name), "/") || strings.Contains(string(setHeader.Name), ":") {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them. Header: '%s'", string(setHeader.Name)),

if !isModifiableHeader(string(setHeader.Name)) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf("ResponseHeaderModifier Filter cannot set headers with a '/' or ':' character in them, or the host header. Header: %q",
string(setHeader.Name)),
)
continue
}
Expand Down Expand Up @@ -738,17 +720,21 @@
}
for _, removedHeader := range headersToRemove {
if removedHeader == "" {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,

Check warning on line 724 in internal/gatewayapi/filters.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/filters.go#L723-L724

Added lines #L723 - L724 were not covered by tests
"ResponseHeaderModifier Filter cannot remove a header with an empty name",
)
continue
}
if !isModifiableHeader(removedHeader) {
updateRouteStatusForRHMFilter(
filterContext,
fmt.Sprintf(
"ResponseHeaderModifier Filter cannot remove headers with a '/' or ':' character in them, or the host header. Header: %q",
removedHeader),
)
continue
}

canRemHeader := true
for _, h := range filterContext.RemoveResponseHeaders {
Expand All @@ -768,13 +754,8 @@

// Update the status if the filter failed to configure any valid headers to add/remove
if len(filterContext.AddResponseHeaders) == 0 && len(filterContext.RemoveResponseHeaders) == 0 && !emptyFilterConfig {
routeStatus := GetRouteStatus(filterContext.Route)
status.SetRouteStatusCondition(routeStatus,
filterContext.ParentRef.routeParentStatusIdx,
filterContext.Route.GetGeneration(),
gwapiv1.RouteConditionAccepted,
metav1.ConditionFalse,
gwapiv1.RouteReasonUnsupportedValue,
updateRouteStatusForRHMFilter(
filterContext,
"ResponseHeaderModifier Filter did not provide valid configuration to add/set/remove any headers",
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ httpRoutes:
rules:
- matches:
- path:
value: "/"
value: "/foo"
backendRefs:
- name: service-1
port: 8080
Expand All @@ -42,7 +42,57 @@ httpRoutes:
value: "some-value"
- name: "good-header"
value: "some-value"
add:
- name: "example/2"
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-2
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- matches:
- path:
value: "/bar"
backendRefs:
- name: service-1
port: 8080
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
remove:
- "example/2"
set:
- name: "good-header"
value: "some-value"
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-3
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- matches:
- path:
value: "/baz"
backendRefs:
- name: service-1
port: 8080
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: "host"
value: "example.com"
- name: "good-header"
value: "some-value"

Loading