spring-cloud / spring-cloud/spring-cloud-gateway
SecureHeaders filter at route level is not working for downloadOptions and permissionPolicy with 2025.0.0
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 4.9k
- Forks
- 3.5k
- Avg merge
- 20h 57m
- Merged PRs (30d)
- 8
Description
Describe the bug
Issue 1: SecureHeaders filter at route level is not working for downloadOptions and permissionPolicy
Works with springCloudVersion: 2024.0.2
spring:
cloud:
gateway:
routes:
- id: api-testing
uri: http://localhost:8081
order: 1
predicates:
- Path=/gateway/api/json/**
filters:
- RewritePath=/gateway/(?<segment>.*), /$\{segment}
- name: SecureHeaders
args:
xssProtectionHeader: route_level
strictTransportSecurity: route_level
contentTypeOptions: route_level
frameOptions: route_level
referrerPolicy: route_level
contentSecurityPolicy: route_level
downloadOptions: route_level
permittedCrossDomainPolicies: route_level
$ curl http://localhost:8080/gateway/api/json/realm -v
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
* using HTTP/1.x
> GET /gateway/api/json/realm HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json
< Matched-Stub-Id: 7f4f6c07-265a-4a95-bf89-82ea01bd919f
< Vary: Accept-Encoding, User-Agent
< X-Xss-Protection: route_level
< Strict-Transport-Security: route_level
< X-Frame-Options: route_level
< X-Content-Type-Options: route_level
< Referrer-Policy: route_level
< Content-Security-Policy: route_level
< X-Download-Options: route_level
< X-Permitted-Cross-Domain-Policies: route_level
Not Working with springCloudVersion: 2025.0.0
The above route configuration doesn't work, so I migrated it as follows:
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: api-testing
uri: http://localhost:8081
order: 1
predicates:
- Path=/gateway/api/json/**
filters:
- RewritePath=/gateway/(?<segment>.*), /$\{segment}
- name: SecureHeaders
args:
xssProtectionHeaderValue: route_level
strictTransportSecurityHeaderValue: route_level
frameOptionsHeaderValue: route_level
contentTypeOptionsHeaderValue: route_level
referrerPolicyHeaderValue: route_level
contentSecurityPolicyHeaderValue: route_level
downloadOptionsHeaderValue: route_level
permittedCrossDomainPoliciesHeaderValue: route_level
permissionPolicyHeaderValue: route_level
$ curl http://localhost:8080/gateway/api/json/realm -v
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
* using HTTP/1.x
> GET /gateway/api/json/realm HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json
< Matched-Stub-Id: 7f4f6c07-265a-4a95-bf89-82ea01bd919f
< Vary: Accept-Encoding, User-Agent
< X-Xss-Protection: route_level
< Strict-Transport-Security: route_level
< X-Frame-Options: route_level
< X-Content-Type-Options: route_level
< Referrer-Policy: route_level
< Content-Security-Policy: route_level
< X-Download-Options: noopen
< X-Permitted-Cross-Domain-Policies: route_level
As observed, the X-Download-Options header is using the default value instead of the one configured at the route level. Additionally, the Permissions-Policy header is missing from the response.
Issue 2: The differing property names between SecureHeadersGatewayFilterFactory.Config and SecureHeadersProperties make the configuration somewhat confusing
SecureHeadersProperties:
private String xssProtectionHeader = X_XSS_PROTECTION_HEADER_DEFAULT;
private String strictTransportSecurity = STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT;
private String frameOptions = X_FRAME_OPTIONS_HEADER_DEFAULT;
private String contentTypeOptions = X_CONTENT_TYPE_OPTIONS_HEADER_DEFAULT;
private String referrerPolicy = REFERRER_POLICY_HEADER_DEFAULT;
private String contentSecurityPolicy = CONTENT_SECURITY_POLICY_HEADER_DEFAULT;
private String downloadOptions = X_DOWNLOAD_OPTIONS_HEADER_DEFAULT;
private String permittedCrossDomainPolicies = X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT;
private String permissionsPolicy = PERMISSIONS_POLICY_HEADER_OPT_IN_DEFAULT;
SecureHeadersGatewayFilterFactory.Config:
private String routePermissionsPolicyHeaderValue;
private String xssProtectionHeaderValue;
private String strictTransportSecurityHeaderValue;
private String frameOptionsHeaderValue;
private String contentTypeOptionsHeaderValue;
private String referrerPolicyHeaderValue;
private String contentSecurityPolicyHeaderValue;
private String downloadOptionsHeaderValue;
private String permittedCrossDomainPoliciesHeaderValue;
private String permissionPolicyHeaderValue;
Also, it's strange we have two properties for permissionPolicy, routePermissionsPolicyHeaderValue and permissionPolicyHeaderValue, neither of which work.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading SecureHeadersGatewayFilterFactory.Config and SecureHeadersProperties, then reproduce the route-level configuration shown for springCloudVersion 2025.0.0. Trace how downloadOptions and permissionPolicy are bound and emitted; done means both configured headers appear with the route values and the related property names behave consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100