此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.1spring-doc.cn

安全 HTTP 响应标头

安全 HTTP 响应标头可用于提高 Web 应用程序的安全性。 本节专门介绍对安全 HTTP 响应标头的基于 servlet 的支持。spring-doc.cn

默认安全标头

Spring Security 提供了一组默认的安全 HTTP 响应 Headers 来提供安全的默认值。 虽然这些标头中的每一个都被视为最佳实践,但应该注意的是,并非所有客户端都使用这些标头,因此鼓励进行额外的测试。spring-doc.cn

您可以自定义特定的标头。 例如,假设您需要默认值,但您希望为 X-Frame-Options 指定。SAMEORIGINspring-doc.cn

您可以使用以下 Configuration 轻松执行此操作:spring-doc.cn

自定义默认安全标头
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options policy="SAMEORIGIN" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
        return http.build()
    }
}

如果您不希望添加默认值并希望明确控制应使用的内容,则可以禁用默认值。 下面提供了一个示例:spring-doc.cn

如果您使用的是 Spring Security 的配置,则以下内容将仅添加 Cache Controlspring-doc.cn

自定义缓存控制标头
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				// do not use any default headers unless explicitly listed
				.defaultsDisabled()
				.cacheControl(withDefaults())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers defaults-disabled="true">
		<cache-control/>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                // do not use any default headers unless explicitly listed
                defaultsDisabled = true
                cacheControl {
                }
            }
        }
        return http.build()
    }
}

如有必要,您可以使用以下配置禁用所有 HTTP 安全响应标头:spring-doc.cn

禁用所有 HTTP 安全标头
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers.disable());
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers disabled="true" />
</http>
@EnableWebSecurity
class SecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                disable()
            }
        }
        return http.build()
    }
}

缓存控制

默认情况下,Spring Security 包括 Cache Control 标头。spring-doc.cn

但是,如果你真的想缓存特定的响应,你的应用程序可以选择性地调用HttpServletResponse.setHeader(String,String)来覆盖 Spring Security 设置的 Header。 这对于确保正确缓存 CSS、JavaScript 和图像等内容非常有用。spring-doc.cn

使用 Spring Web MVC 时,这通常在您的配置中完成。 有关如何执行此操作的详细信息,请参阅 Spring 参考文档的 Static Resources 部分spring-doc.cn

如有必要,您还可以禁用 Spring Security 的缓存控制 HTTP 响应标头。spring-doc.cn

已禁用缓存控制
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.cacheControl(cache -> cache.disable())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<cache-control disabled="true"/>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
       http {
            headers {
                cacheControl {
                    disable()
                }
            }
        }
        return http.build()
    }
}

内容类型选项

Spring Security 默认包括 Content-Type 标头。 但是,您可以通过以下方式禁用它:spring-doc.cn

内容类型选项已禁用
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-type-options disabled="true"/>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
       http {
            headers {
                contentTypeOptions {
                    disable()
                }
            }
        }
        return http.build()
    }
}

HTTP 严格传输安全 (HSTS)

Spring Security 默认提供 Strict Transport Security Headers。 但是,您可以显式自定义结果。 例如,以下是显式提供 HSTS 的示例:spring-doc.cn

严格的运输安全
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpStrictTransportSecurity(hsts -> hsts
					.includeSubDomains(true)
					.preload(true)
					.maxAgeInSeconds(31536000)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<hsts
			include-subdomains="true"
			max-age-seconds="31536000"
			preload="true" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                httpStrictTransportSecurity {
                    includeSubDomains = true
                    preload = true
                    maxAgeInSeconds = 31536000
                }
            }
        }
        return http.build()
    }
}

HTTP 公钥固定 (HPKP)

出于被动原因, Spring Security 为 HTTP 公钥固定提供了 servlet 支持,但不再推荐使用。spring-doc.cn

您可以使用以下配置启用 HPKP 标头:spring-doc.cn

HTTP 公钥固定
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.httpPublicKeyPinning(hpkp -> hpkp
					.includeSubDomains(true)
					.reportUri("https://example.net/pkp-report")
					.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<hpkp
			include-subdomains="true"
			report-uri="https://example.net/pkp-report">
			<pins>
				<pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
				<pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
			</pins>
		</hpkp>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                httpPublicKeyPinning {
                    includeSubDomains = true
                    reportUri = "https://example.net/pkp-report"
                    pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256",
                            "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256")
                }
            }
        }
        return http.build()
    }
}

X 框架选项

默认情况下,Spring Security 使用 X-Frame-Options 禁用 iframe 中的渲染。spring-doc.cn

您可以使用以下内容自定义框架选项,以便在 Configuration 中使用相同的源:spring-doc.cn

X 框架选项:SAMEORIGIN
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions
					.sameOrigin()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options
		policy="SAMEORIGIN" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
        return http.build()
    }
}

X-XSS 保护

默认情况下,Spring Security 指示浏览器使用<<headers-xss-protection,X-XSS-Protection标头>来阻止反射的 XSS 攻击。 但是,您可以更改此默认值。 例如,以下 Configuration 指定 Spring Security 不应再指示浏览器阻止内容:spring-doc.cn

X-XSS-Protection 定制
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.xssProtection(xss -> xss
					.block(false)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<xss-protection block="false"/>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        // ...
        http {
            headers {
                xssProtection {
                    block = false
                }
            }
        }
        return http.build()
    }
}

内容安全策略 (CSP)

默认情况下, Spring Security 不添加内容安全策略,因为如果没有应用程序的上下文,就不可能知道合理的默认值。 Web 应用程序作者必须声明安全策略,以强制实施和/或监控受保护的资源。spring-doc.cn

例如,给定以下安全策略:spring-doc.cn

内容安全策略示例
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/

您可以启用 CSP 标头,如下所示:spring-doc.cn

内容安全策略
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                }
            }
        }
        return http.build()
    }
}

要启用 CSP 标头,请提供以下配置:report-onlyspring-doc.cn

仅内容安全策略报告
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.contentSecurityPolicy(csp -> csp
					.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
					.reportOnly()
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<content-security-policy
			policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
			report-only="true" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                contentSecurityPolicy {
                    policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
                    reportOnly = true
                }
            }
        }
        return http.build()
    }
}

反向链接策略

默认情况下,Spring Security 不添加 Referrer Policy 标头。 您可以使用配置启用 Referrer Policy 标头,如下所示:spring-doc.cn

反向链接策略
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.referrerPolicy(referrer -> referrer
					.policy(ReferrerPolicy.SAME_ORIGIN)
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<referrer-policy policy="same-origin" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                referrerPolicy {
                    policy = ReferrerPolicy.SAME_ORIGIN
                }
            }
        }
        return http.build()
    }
}

功能策略

默认情况下,Spring Security 不添加 Feature Policy 标头。 以下标头:Feature-Policyspring-doc.cn

功能策略示例
Feature-Policy: geolocation 'self'

可以使用如下所示的配置启用 Feature Policy 标头:spring-doc.cn

功能策略
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.featurePolicy("geolocation 'self'")
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<feature-policy policy-directives="geolocation 'self'" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                featurePolicy("geolocation 'self'")
            }
        }
        return http.build()
    }
}

权限策略

默认情况下,Spring Security 不添加 Permissions Policy 标头。 以下标头:Permissions-Policyspring-doc.cn

Permissions-Policy 示例
Permissions-Policy: geolocation=(self)

可以使用如下所示的配置启用 Permissions Policy 标头:spring-doc.cn

权限策略
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.permissionsPolicy(permissions -> permissions
					.policy("geolocation=(self)")
				)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<permissions-policy policy="geolocation=(self)" />
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                permissionPolicy {
                    policy = "geolocation=(self)"
                }
            }
        }
        return http.build()
    }
}

清除站点数据

默认情况下,Spring Security 不添加 Clear-Site-Data 标头。 以下 Clear-Site-Data 标头:spring-doc.cn

Clear-Site-Data 示例
Clear-Site-Data: "cache", "cookies"

可以使用以下配置在注销时发送:spring-doc.cn

清除站点数据
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.logout((logout) -> logout
                .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))
			);
		return http.build();
	}
}
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            logout {
                addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES)))
            }
        }
        return http.build()
    }
}

跨域策略

Spring Security 为添加一些跨域策略 Headers 提供了内置支持,这些 Headers 是:spring-doc.cn

Cross-Origin-Opener-Policy
Cross-Origin-Embedder-Policy
Cross-Origin-Resource-Policy

默认情况下,Spring Security 不添加跨域策略 Headers。 可以使用以下配置添加标头:spring-doc.cn

跨域策略
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) {
        http.headers((headers) -> headers
                .crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
                .crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
                .crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)));
        return http.build();
    }
}
@EnableWebSecurity
open class CrossOriginPoliciesConfig {
    @Bean
    open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            headers {
                crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
                crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
                crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)
            }
        }
        return http.build()
    }
}

此配置将使用提供的值写入标头:spring-doc.cn

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin

自定义标头

Spring Security 具有一些机制,可以方便地将更常见的安全 Headers 添加到您的应用程序中。 但是,它还提供了 hook 来启用添加自定义标头。spring-doc.cn

静态标头

有时您可能希望将自定义安全标头注入到应用程序中,而这些标头并非开箱即用。 例如,给定以下自定义安全标头:spring-doc.cn

X-Custom-Security-Header: header-value

可以使用以下 Configuration 将标头添加到响应中:spring-doc.cn

静态标头写入器
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<header name="X-Custom-Security-Header" value="header-value"/>
	</headers>
</http>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value"))
            }
        }
        return http.build()
    }
}

标头写入器

当命名空间或 Java 配置不支持所需的标头时,您可以创建自定义实例,甚至可以提供 .HeadersWriterHeadersWriterspring-doc.cn

让我们看一个使用 . 如果您想显式配置 X-Frame-Options,可以使用以下 Configuration 来完成:XFrameOptionsHeaderWriterspring-doc.cn

标头写入器
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.headers(headers -> headers
				.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<header ref="frameOptionsWriter"/>
	</headers>
</http>
<!-- Requires the c-namespace.
See https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-c-namespace
-->
<beans:bean id="frameOptionsWriter"
	class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"
	c:frameOptionsMode="SAMEORIGIN"/>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // ...
            headers {
                addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
            }
        }
        return http.build()
    }
}

委托RequestMatcherHeaderWriter

有时,您可能只想为某些请求编写标头。 例如,也许您只想保护登录页面不被框架化。 您可以使用 来执行此操作。DelegatingRequestMatcherHeaderWriterspring-doc.cn

在 Java 配置中使用的示例如下所示:DelegatingRequestMatcherHeaderWriterspring-doc.cn

DelegatingRequestMatcherHeaderWriter Java 配置
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		RequestMatcher matcher = new AntPathRequestMatcher("/login");
		DelegatingRequestMatcherHeaderWriter headerWriter =
			new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
		http
			// ...
			.headers(headers -> headers
				.frameOptions(frameOptions -> frameOptions.disable())
				.addHeaderWriter(headerWriter)
			);
		return http.build();
	}
}
<http>
	<!-- ... -->

	<headers>
		<frame-options disabled="true"/>
		<header ref="headerWriter"/>
	</headers>
</http>

<beans:bean id="headerWriter"
	class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
	<beans:constructor-arg>
		<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"
			c:pattern="/login"/>
	</beans:constructor-arg>
	<beans:constructor-arg>
		<beans:bean
			class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"/>
	</beans:constructor-arg>
</beans:bean>
@EnableWebSecurity
class SecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        val matcher: RequestMatcher = AntPathRequestMatcher("/login")
        val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter())
       http {
            headers {
                frameOptions {
                    disable()
                }
                addHeaderWriter(headerWriter)
            }
        }
        return http.build()
    }
}