安全響應(yīng)頭
1. 前言
上節(jié)我們討論了 Spring Security 如何防范 CSRF 攻擊,本節(jié)我們討論如何用最簡單的方式提升 Spring Security Web 項目的安全性。
Spring Security 可以通過「HTTP 安全響應(yīng)頭」的方式提升安全性。
本節(jié)我們討論如何實現(xiàn) HTTP 安全響應(yīng)頭。
2. 安全響應(yīng)頭
Spring Security 提供了一些默認(rèn) HTTP 安全性相關(guān)的響應(yīng)頭。這些默認(rèn)響應(yīng)頭如下:
2.1 Cache-Control
當(dāng)用戶通過了認(rèn)證,訪問了敏感信息而后點擊了退出,此時若瀏覽器對頁面進(jìn)行了緩存,攻擊者就可能通過點擊瀏覽器「后退」按鍵訪問到剛剛認(rèn)證用戶看到的內(nèi)容。
Spring Security 默認(rèn)禁用瀏覽器頁面緩存,這樣可以減少敏感信息泄漏風(fēng)險。
2.2 Content Type Options
瀏覽器為了增強用戶體驗,會去嗅探用戶請求的內(nèi)容格式。例如當(dāng)瀏覽器訪問到某個 JavaScript 文件,然而此時并沒有指定其文件類型,此時瀏覽器則會自動判斷并且執(zhí)行它。
內(nèi)容嗅探帶來了一些問題,比如攻擊者會利用某些可被解析成多種內(nèi)容格式的文件,執(zhí)行 XSS 攻擊。例如,有些網(wǎng)站可能允許用戶上傳和預(yù)覽 PostScript 代碼,攻擊者創(chuàng)建一個 PostScript 文檔,同時該文檔也是一個 JavaScript 格式文件,此時,攻擊者便可以實現(xiàn) XSS 攻擊。
Spring Security 默認(rèn)禁用了內(nèi)容嗅探功能。
2.3 HTTP Strict Transport Security (HSTS)
通常我們訪問網(wǎng)站的時候是直接輸入域名,比如:mybank.example.com,此時默認(rèn)情況下瀏覽器會訪問 http://mybank.example.com。HTTP 協(xié)議由于信息不加密,無法保證訪問目標(biāo)的真實性,容易受到中間人攻擊。增加 Strict-Transport-Security 響應(yīng)頭,可以強制將訪問協(xié)議轉(zhuǎn)換成 Https。
2.4 X-Frame-Options
允許網(wǎng)站被放到 iframe 對象里,這種情況下攻擊者可能通過設(shè)置 CSS,讓用戶的點擊發(fā)生在非意愿的位置。
默認(rèn)情況下 Spring Security 拒絕網(wǎng)頁在 iframe 對象中渲染。
2.5 X-XSS-Protection
盡管大部分瀏覽器都已經(jīng)內(nèi)置了過濾 XSS 攻擊的支持,但也并非所有瀏覽器都默認(rèn)支持。增加 XSS-Protection 頭可以確保 XSS 攻擊過濾已啟動。
3. Spring Security 配置
3.1 默認(rèn)的安全頭配置
Spring Security 提供了一系列默認(rèn) Http 安全響應(yīng)頭,我們可以便捷的配置它們。
例如,為 X-Frame-Options
指定值 SAMEORIGIN
:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()));
}
}
如果不希望默認(rèn)頭被自動添加,可以通過如下方式配置,例如僅添加 Cache Control 頭:
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.headers(headers -> headers
// 取消自動添加默認(rèn)頭
.defaultsDisabled()
// 添加 CacheControl 頭
.cacheControl(withDefaults())
);
}
}
或者通過以下方式禁用所有 HTTP 安全響應(yīng)頭:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers(headers -> headers.disable());
}
}
3.2 Cache Control
Spring Security 默認(rèn)包含「Cache Control」頭。
如果只需要緩存指定類型的內(nèi)容,我們可以通過 HttpServletResponse.setHeader(String,String)
方式指定緩存項,如 CSS、JavaScript、圖片等。
我們也可以直接禁用掉「Cache Control」頭,方式如下:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http.headers(headers -> headers.cacheControl(cache -> cache.disable()));
}
}
3.3 Content-Type 頭
Spring Security 默認(rèn)包含了 Content-Type
頭。如果需要禁用它,可以通過如下方式:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http.headers(headers -> headers.contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable()));
}
}
3.4 HSTS 頭
HTTP Strict Transport Security(HSTS)頭,在 Spring Security 中是被默認(rèn)開啟的,我們可以修改它的默認(rèn)狀態(tài),如下:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.preload(true)
.maxAgeInSeconds(31536000)
)
);
}
}
3.5 X-Frame-Options 頭
默認(rèn)情況下,Spring Security 通過 X-Frame-Options 頭方式禁止 iframe 層渲染,我們可以通過如下方式修改其配置:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()));
}
}
3.6 X-XSS-Protection 頭
默認(rèn)情況下,Spring Security 為了防止 XSS 攻擊增加了 X-XSS-Protection 頭,我們可以通過以下方式對其配置進(jìn)行修改:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers(headers -> headers.xssProtection(xss -> xss.block(false)));
}
}
3.7 自定義響應(yīng)頭
Spring Security 的實現(xiàn)機制使得它可以輕易的添加安全響應(yīng)頭。
3.7.1 靜態(tài)頭
例如配置如下自定義頭:
X-Custom-Security-Header: header-value
我們可以通過 StaticHeadersWriter 對象添加:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers(headers -> headers.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value")));
}
}
3.7.2 動態(tài)添加
當(dāng)Spring Security 的默認(rèn)配置方式不能滿足我們添加響應(yīng)頭的需求時,我們可以通過 HeadersWriter
實例動態(tài)添加。例如動態(tài)添加 X-Frame-Options
頭:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers(headers -> headers.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)));
}
}
3.7.3 為指定請求添加響應(yīng)頭
有時候我們只想為某個確定的請求添加響應(yīng)頭,例如只針對對登錄頁面的請求,這是可以通過 DelegatingRequestMatcherHeaderWriter
實現(xiàn)。例如:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(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));
}
}
4. 小結(jié)
本節(jié)討論了如何利用 HTTP 請求頭提升 Spring Security Web 項目的安全性,主要內(nèi)容有:
- Http 安全響應(yīng)頭是提升 B/S 應(yīng)用安全性的有效手段;
- Spring Security 默認(rèn)實現(xiàn)了常用的安全響應(yīng)頭;
- Spring Security 可以通過配置類,直接開啟、關(guān)閉或調(diào)整各個內(nèi)置請求頭的狀態(tài)及參數(shù);
- Spring Security 提供了靜態(tài)設(shè)置響應(yīng)頭的方法;
- Spring Security 支持動態(tài)添加響應(yīng)頭;
- Spring Security 支持針對某個特殊請求動態(tài)設(shè)置響應(yīng)頭。
下節(jié)我們討論針對 HTTP 協(xié)議,我們還能有哪些安全性提升策略。