安全 HTTP 響應頭
您可以使用 安全 HTTP 響應頭 來提高 Web 應用程式的安全性。本節專門介紹基於 servlet 的安全 HTTP 響應頭支援。
預設安全頭
Spring Security 提供了一組 預設的安全 HTTP 響應頭,以提供安全的預設值。雖然這些頭都被認為是最佳實踐,但需要注意的是,並非所有客戶端都使用這些頭,因此建議進行額外的測試。
您可以自定義特定的頭。例如,假設您希望使用預設值,但希望為 X-Frame-Options 指定 SAMEORIGIN。
您可以使用以下配置進行此操作
-
Java
-
XML
-
Kotlin
@Configuration
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
headers {
frameOptions {
sameOrigin = true
}
}
}
return http.build()
}
}
如果您不希望新增預設值,並希望對使用哪些值進行顯式控制,則可以停用預設值。以下程式碼清單演示瞭如何實現這一點。
如果您使用 Spring Security 的配置,以下程式碼僅新增 快取控制
-
Java
-
XML
-
Kotlin
@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>
<!-- ... -->
<headers defaults-disabled="true">
<cache-control/>
</headers>
</http>
@Configuration
@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 安全響應頭
-
Java
-
XML
-
Kotlin
@Configuration
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
headers {
disable()
}
}
return http.build()
}
}
快取控制
Spring Security 預設包含 快取控制 頭。
但是,如果您確實希望快取特定響應,您的應用程式可以選擇性地呼叫 HttpServletResponse.setHeader(String,String) 來覆蓋 Spring Security 設定的頭。您可以使用此功能確保內容(如 CSS、JavaScript 和影像)得到正確快取。
當您使用 Spring Web MVC 時,這通常是在您的配置中完成的。您可以在 Spring 參考文件的 靜態資源 部分找到有關如何執行此操作的詳細資訊
如有必要,您還可以停用 Spring Security 的快取控制 HTTP 響應頭。
-
Java
-
XML
-
Kotlin
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
headers {
cacheControl {
disable()
}
}
}
return http.build()
}
}
內容型別選項
Spring Security 預設包含 Content-Type 頭。但是,您可以停用它
-
Java
-
XML
-
Kotlin
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
headers {
contentTypeOptions {
disable()
}
}
}
return http.build()
}
}
HTTP 嚴格傳輸安全 (HSTS)
預設情況下,Spring Security 提供 嚴格傳輸安全 頭。但是,您可以顯式自定義結果。以下示例顯式提供 HSTS
-
Java
-
XML
-
Kotlin
@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>
<!-- ... -->
<headers>
<hsts
include-subdomains="true"
max-age-seconds="31536000"
preload="true" />
</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
headers {
httpStrictTransportSecurity {
includeSubDomains = true
preload = true
maxAgeInSeconds = 31536000
}
}
}
return http.build()
}
}
HTTP 公鑰固定 (HPKP)
您可以使用以下配置啟用 HPKP 頭
-
Java
-
XML
-
Kotlin
@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();
}
}
<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>
@Configuration
@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-Frame-Options
預設情況下,Spring Security 指示瀏覽器使用 X-Frame-Options 阻止反射型 XSS 攻擊。
例如,以下配置指定 Spring Security 不再指示瀏覽器阻止內容
-
Java
-
XML
-
Kotlin
@Configuration
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
headers {
frameOptions {
sameOrigin = true
}
}
}
return http.build()
}
}
X-XSS-Protection
預設情況下,Spring Security 透過使用 <<headers-xss-protection,X-XSS-Protection 頭>指示瀏覽器停用 XSS 審計器。但是,您可以更改此預設設定。例如,以下配置指定 Spring Security 指示相容瀏覽器啟用過濾並阻止內容
-
Java
-
XML
-
Kotlin
@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();
}
}
<http>
<!-- ... -->
<headers>
<xss-protection headerValue="1; mode=block"/>
</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
// ...
http {
headers {
xssProtection {
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 頭
-
Java
-
XML
-
Kotlin
@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();
}
}
<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>
@Configuration
@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-only 頭,請提供以下配置
-
Java
-
XML
-
Kotlin
@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();
}
}
<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>
@Configuration
@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 預設不新增 引用者策略 頭。您可以使用以下配置啟用引用者策略頭
-
Java
-
XML
-
Kotlin
@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();
}
}
<http>
<!-- ... -->
<headers>
<referrer-policy policy="same-origin" />
</headers>
</http>
@Configuration
@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-Policy: geolocation 'self'
您可以使用以下配置啟用上述特性策略頭
-
Java
-
XML
-
Kotlin
@Configuration
@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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
headers {
featurePolicy("geolocation 'self'")
}
}
return http.build()
}
}
許可權策略
Spring Security 預設不新增 許可權策略 頭。考慮以下 Permissions-Policy 頭
Permissions-Policy: geolocation=(self)
您可以使用以下配置啟用上述許可權策略頭
-
Java
-
XML
-
Kotlin
@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();
}
}
<http>
<!-- ... -->
<headers>
<permissions-policy policy="geolocation=(self)" />
</headers>
</http>
@Configuration
@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: "cache", "cookies"
您可以使用以下配置在登出時傳送上述頭
-
Java
-
Kotlin
@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();
}
}
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
logout {
addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES)))
}
}
return http.build()
}
}
自定義頭
Spring Security 具有方便的機制,可以向您的應用程式新增更常見的安全頭。但是,它也提供了啟用新增自定義頭的鉤子。
靜態頭
有時,您可能希望將開箱即用不支援的自定義安全頭注入到您的應用程式中。考慮以下自定義安全頭
X-Custom-Security-Header: header-value
根據上述頭,您可以使用以下配置將頭新增到響應中
-
Java
-
XML
-
Kotlin
@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();
}
}
<http>
<!-- ... -->
<headers>
<header name="X-Custom-Security-Header" value="header-value"/>
</headers>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
headers {
addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value"))
}
}
return http.build()
}
}
頭寫入器
當名稱空間或 Java 配置不支援您想要的頭時,您可以建立自定義的 HeadersWriter 例項,甚至提供 HeadersWriter 的自定義實現。
下一個示例使用 XFrameOptionsHeaderWriter 的自定義例項。如果您想顯式配置 X-Frame-Options,您可以使用以下配置進行操作
-
Java
-
XML
-
Kotlin
@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();
}
}
<http>
<!-- ... -->
<headers>
<header ref="frameOptionsWriter"/>
</headers>
</http>
<!-- Requires the c-namespace.
See https://docs.springframework.tw/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"/>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
headers {
addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
}
}
return http.build()
}
}
DelegatingRequestMatcherHeaderWriter
有時,您可能只想為某些請求寫入頭。例如,也許您只想保護您的登入頁面不被框架。您可以使用 DelegatingRequestMatcherHeaderWriter 來實現這一點。
以下配置示例使用 DelegatingRequestMatcherHeaderWriter
-
Java
-
XML
-
Kotlin
@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();
}
}
<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.config.http.PathPatternRequestMatcherFactoryBean"
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>
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
val matcher: RequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/login")
val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter())
http {
headers {
frameOptions {
disable()
}
addHeaderWriter(headerWriter)
}
}
return http.build()
}
}