本文主要研究下spring cloud gateway的SecureHeadersGatewayFilterhtml
@Configuration @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) @EnableConfigurationProperties @AutoConfigureBefore(HttpHandlerAutoConfiguration.class) @AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class}) @ConditionalOnClass(DispatcherHandler.class) public class GatewayAutoConfiguration { //...... @Bean public SecureHeadersGatewayFilterFactory secureHeadersGatewayFilterFactory(SecureHeadersProperties properties) { return new SecureHeadersGatewayFilterFactory(properties); } //...... }
{ "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'", "name": "spring.cloud.gateway.filter.secure-headers.content-security-policy", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "nosniff", "name": "spring.cloud.gateway.filter.secure-headers.content-type-options", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "noopen", "name": "spring.cloud.gateway.filter.secure-headers.download-options", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "DENY", "name": "spring.cloud.gateway.filter.secure-headers.frame-options", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "none", "name": "spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "no-referrer", "name": "spring.cloud.gateway.filter.secure-headers.referrer-policy", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "max-age=631138519", "name": "spring.cloud.gateway.filter.secure-headers.strict-transport-security", "type": "java.lang.String" }, { "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties", "defaultValue": "1 ; mode=block", "name": "spring.cloud.gateway.filter.secure-headers.xss-protection-header", "type": "java.lang.String" }
spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.javajava
@ConfigurationProperties("spring.cloud.gateway.filter.secure-headers") public class SecureHeadersProperties { public static final String X_XSS_PROTECTION_HEADER_DEFAULT = "1 ; mode=block"; public static final String STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT = "max-age=631138519"; //; includeSubDomains preload") public static final String X_FRAME_OPTIONS_HEADER_DEFAULT = "DENY"; //SAMEORIGIN = ALLOW-FROM public static final String X_CONTENT_TYPE_OPTIONS_HEADER_DEFAULT = "nosniff"; public static final String REFERRER_POLICY_HEADER_DEFAULT = "no-referrer"; //no-referrer-when-downgrade = origin = origin-when-cross-origin = same-origin = strict-origin = strict-origin-when-cross-origin = unsafe-url public static final String CONTENT_SECURITY_POLICY_HEADER_DEFAULT = "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'"; public static final String X_DOWNLOAD_OPTIONS_HEADER_DEFAULT = "noopen"; public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT = "none"; 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; //...... @Override public String toString() { final StringBuffer sb = new StringBuffer("SecureHeadersProperties{"); sb.append("xssProtectionHeader='").append(xssProtectionHeader).append('\''); sb.append(", strictTransportSecurity='").append(strictTransportSecurity).append('\''); sb.append(", frameOptions='").append(frameOptions).append('\''); sb.append(", contentTypeOptions='").append(contentTypeOptions).append('\''); sb.append(", referrerPolicy='").append(referrerPolicy).append('\''); sb.append(", contentSecurityPolicy='").append(contentSecurityPolicy).append('\''); sb.append(", downloadOptions='").append(downloadOptions).append('\''); sb.append(", permittedCrossDomainPolicies='").append(permittedCrossDomainPolicies).append('\''); sb.append('}'); return sb.toString(); } }
spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.javaspring
/** * https://blog.appcanary.com/2017/http-security-headers.html * @author Spencer Gibb */ public class SecureHeadersGatewayFilterFactory extends AbstractGatewayFilterFactory { public static final String X_XSS_PROTECTION_HEADER = "X-Xss-Protection"; public static final String STRICT_TRANSPORT_SECURITY_HEADER = "Strict-Transport-Security"; public static final String X_FRAME_OPTIONS_HEADER = "X-Frame-Options"; public static final String X_CONTENT_TYPE_OPTIONS_HEADER = "X-Content-Type-Options"; public static final String REFERRER_POLICY_HEADER = "Referrer-Policy"; public static final String CONTENT_SECURITY_POLICY_HEADER = "Content-Security-Policy"; public static final String X_DOWNLOAD_OPTIONS_HEADER = "X-Download-Options"; public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = "X-Permitted-Cross-Domain-Policies"; private final SecureHeadersProperties properties; public SecureHeadersGatewayFilterFactory(SecureHeadersProperties properties) { this.properties = properties; } @Override public GatewayFilter apply(Object config) { //TODO: allow args to override properties return (exchange, chain) -> { HttpHeaders headers = exchange.getResponse().getHeaders(); //TODO: allow header to be disabled headers.add(X_XSS_PROTECTION_HEADER, properties.getXssProtectionHeader()); headers.add(STRICT_TRANSPORT_SECURITY_HEADER, properties.getStrictTransportSecurity()); headers.add(X_FRAME_OPTIONS_HEADER, properties.getFrameOptions()); headers.add(X_CONTENT_TYPE_OPTIONS_HEADER, properties.getContentTypeOptions()); headers.add(REFERRER_POLICY_HEADER, properties.getReferrerPolicy()); headers.add(CONTENT_SECURITY_POLICY_HEADER, properties.getContentSecurityPolicy()); headers.add(X_DOWNLOAD_OPTIONS_HEADER, properties.getDownloadOptions()); headers.add(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, properties.getPermittedCrossDomainPolicies()); return chain.filter(exchange); }; } }
能夠看到該filter往response的header添加一系列的security相關的headerapp
SecureHeadersGatewayFilter往response添加了以下headerdom
spring.cloud.gateway.filter.secure-headers.xss-protection-header=1 ; mode=blockxss
spring.cloud.gateway.filter.secure-headers.strict-transport-security=max-age=631138519ide
spring.cloud.gateway.filter.secure-headers.frame-options=DENYoop
spring.cloud.gateway.filter.secure-headers.content-type-options=nosniffthis
spring.cloud.gateway.filter.secure-headers.referrer-policy=no-referrerurl
spring.cloud.gateway.filter.secure-headers.content-security-policy=default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
spring.cloud.gateway.filter.secure-headers.download-options=noopen
spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies=none