跳到主要内容
版本:7.0.2

安全 HTTP 响应头

DeepSeek V3 中英对照 Security HTTP Response Headers

您可以使用安全HTTP响应头来增强Web应用程序的安全性。本节专门介绍基于Servlet的安全HTTP响应头支持。

默认安全标头

Spring Security 提供了一套默认的 Security HTTP 响应头集以提供安全的默认配置。虽然这些头部都被视为最佳实践,但需要注意的是,并非所有客户端都使用这些头部,因此建议进行额外的测试。

您可以自定义特定的响应头。例如,假设您希望使用默认设置,但需要为 X-Frame-Options 指定 SAMEORIGIN

您可以通过以下配置实现:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

如果您不希望添加默认配置,并希望明确控制应使用的内容,可以禁用默认设置。以下代码清单展示了如何实现此操作。

如果您使用Spring Security的配置,以下内容仅添加缓存控制

@Configuration
@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安全响应头:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

缓存控制

Spring Security 默认包含缓存控制头部。

然而,如果您确实希望缓存特定的响应,您的应用程序可以有选择地调用 HttpServletResponse.setHeader(String,String) 来覆盖 Spring Security 设置的响应头。您可以使用此方法来确保内容(例如 CSS、JavaScript 和图像)被正确缓存。

当您使用 Spring Web MVC 时,这通常是在您的配置中完成的。您可以在 Spring 参考文档的 静态资源 部分找到如何执行此操作的详细信息。

如有必要,您也可以禁用Spring Security的缓存控制HTTP响应头。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

内容类型选项

Spring Security 默认包含 Content-Type 头部。不过,你也可以禁用它:

@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 严格传输安全(HSTS)

默认情况下,Spring Security 提供 Strict Transport Security 头部。然而,你也可以显式地自定义结果。以下示例显式地提供了 HSTS:

@Configuration
@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 公钥固定 (HPKP)

Spring Security 为 HTTP公钥固定 提供了 Servlet 支持,但该功能已 不再推荐使用

您可以通过以下配置启用 HPKP 头:

@Configuration
@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();
}
}

X-Frame-Options

默认情况下,Spring Security 通过使用 X-Frame-Options 来指示浏览器阻止反射型 XSS 攻击。

例如,以下配置指定Spring Security不再指示浏览器阻止内容:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

X-XSS-Protection

默认情况下,Spring Security 通过使用 <<headers-xss-protection,X-XSS-Protection header> 来指示浏览器禁用 XSS 审计器。但是,您可以更改此默认设置。例如,以下配置指定 Spring Security 指示兼容的浏览器启用过滤并阻止内容:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.headers((headers) -> headers
.xssProtection((xss) -> xss
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
)
);
return http.build();
}
}

内容安全策略(CSP)

Spring Security 默认不会添加内容安全策略,因为在不知道应用程序上下文的情况下,无法确定合理的默认策略。Web 应用程序的作者必须声明要强制执行或监控受保护资源的安全策略。

考虑以下安全策略:

Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/

根据前述安全策略,您可以启用CSP头部:

@Configuration
@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();
}
}

要启用 CSP report-only 标头,请提供以下配置:

@Configuration
@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();
}
}

Referrer Policy

Spring Security 默认不添加 Referrer Policy 标头。您可以通过以下配置启用 Referrer Policy 标头:

@Configuration
@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();
}
}

功能策略

Spring Security 默认不会添加功能策略头部。请参考以下 Feature-Policy 头部示例:

Feature-Policy: geolocation 'self'

您可以通过以下配置启用前述功能策略标头:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

权限策略

Spring Security 默认不添加 Permissions Policy 头部。请考虑以下 Permissions-Policy 头部:

Permissions-Policy: geolocation=(self)

您可以通过以下配置启用上述权限策略头:

@Configuration
@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();
}
}

清除网站数据

Spring Security 默认不会添加 Clear-Site-Data 标头。请考虑以下 Clear-Site-Data 标头:

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

您可以通过以下配置在注销时发送前述标头:

@Configuration
@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();
}
}

自定义请求头

Spring Security 提供了便捷的机制,可以将更常见的安全标头添加到您的应用程序中。同时,它也提供了钩子功能,支持添加自定义标头。

静态头部

有时,您可能希望向应用程序注入自定义安全标头,而这些标头并非开箱即用。请考虑以下自定义安全标头:

X-Custom-Security-Header: header-value

根据前面的头部信息,您可以通过以下配置将头部添加到响应中:

@Configuration
@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();
}
}

标头写入器

当命名空间或Java配置不支持你所需的头部信息时,你可以创建一个自定义的 HeadersWriter 实例,甚至提供一个自定义的 HeadersWriter 实现。

下一个示例使用了自定义的 XFrameOptionsHeaderWriter 实例。如果您想显式配置 X-Frame-Options,可以通过以下配置实现:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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

DelegatingRequestMatcherHeaderWriter

有时,您可能只想为特定请求写入响应头。例如,您可能希望仅保护登录页面不被嵌套在框架中。这时可以使用 DelegatingRequestMatcherHeaderWriter 来实现。

以下配置示例使用了 DelegatingRequestMatcherHeaderWriter

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

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