HTTP響應頭處理
HTTP響應頭中的許多屬性都可以用來提高Web安全。我們來看一下Spring Security中提供顯示支持的一些HTTP響應頭
Spring Security默認情況下 顯式支持的HTTP相應頭主要有以下幾種:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
這些響應頭都是在HeaderWriterFilter中添加的,默認情況下,該過濾器就會添加到Spring Security過濾器鏈中,HeaderWriterFilter是通過HeadersConfigure進行配置的,我們看一下HeadersConfigure的幾個關鍵方法
public void configure(H http) {
HeaderWriterFilter headersFilter = this.createHeaderWriterFilter();
http.addFilter(headersFilter);
}
private HeaderWriterFilter createHeaderWriterFilter() {
List<HeaderWriter> writers = this.getHeaderWriters();
if (writers.isEmpty()) {
throw new IllegalStateException("Headers security is enabled, but no headers will be added. Either add headers or disable headers security");
} else {
HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers);
headersFilter = (HeaderWriterFilter)this.postProcess(headersFilter);
return headersFilter;
}
}
private List<HeaderWriter> getHeaderWriters() {
List<HeaderWriter> writers = new ArrayList();
this.addIfNotNull(writers, this.contentTypeOptions.writer);
this.addIfNotNull(writers, this.xssProtection.writer);
this.addIfNotNull(writers, this.cacheControl.writer);
this.addIfNotNull(writers, this.hsts.writer);
this.addIfNotNull(writers, this.frameOptions.writer);
this.addIfNotNull(writers, this.hpkp.writer);
this.addIfNotNull(writers, this.contentSecurityPolicy.writer);
this.addIfNotNull(writers, this.referrerPolicy.writer);
this.addIfNotNull(writers, this.featurePolicy.writer);
this.addIfNotNull(writers, this.permissionsPolicy.writer);
writers.addAll(this.headerWriters);
return writers;
}
可以看到這里在configure方法中創建了HeaderWriterFilter過濾器,在過濾器創建時,通過getHeaderWriters方法獲取到所有需要添加的相應頭傳入過濾器中。getHeaderWriters方法執行時,只會添加不為null的實例,默認情況下只有前五個不為null
其中:
contentTypeOptions.writer負責處理X-Content-Type-Options響應頭
xssProtection.writer負責處理X-XSS-Protection
cacheControl.writer負責處理Cache-Control,Pragma,Expires響應頭
hsts.writer負責處理Strict-Transport-Security響應頭
frameOptions.writer負責處理X-Frame-Options響應頭
接下來我們逐個分析:
緩存控制
和緩存控制有關的響應頭一共有三個:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Cache-Control:Cathe-Control是HTTP/1.1中引入的緩存字段,無論是請求頭還是相應頭都支持該字段,其中no-store表示不做任何緩存,每次請求都會從服務端完整的下載內容,no-cache則表示緩存但是需要重新驗證,這種情況下,數據雖然緩存在客戶端,但是當需要使用該數據時,還是會向服務端發送請求,服務端則驗證請求中所描述的緩存是否過期,如果沒有過期,則返回304,客戶端使用緩存,如果已經過期,則返回最新數據,max-age則表示緩存的有效期,這個有效期並非一個時間戳,而是一個秒數,指從請求發起后多少秒內緩存有效。must-revalidate表示當緩存在使用一個陳舊的資源時,必須先驗證它的狀態,已過期的將不被使用。
Pragma:Pragma是HTTP/1.0中定義的響應頭,作用類似於Cache-Control:no-cache,但是不能代替Cache-Control,該字段主要用來兼容HTTP/1.0的客戶端
Expires:Expires響應頭制定了一個日期,即在指定日期之后,緩存過期。如果日期為0的話,表示緩存已經過期。
從上面的解釋可以看到,Spring Security默認不做任何緩存,需要注意的是,這個是針對經過Spring Security過濾器的請求。如果請求本身沒有經過過濾器鏈,那么該緩存的還是會緩存。
如果請求經過Spring Security過濾器鏈,又希望開啟緩存功能,那么可以關閉Spring Security中關於緩存的默認配置
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.cacheControl()
.disable();
}
X-Content-Type-Options
MIME嗅探:一般來說,瀏覽器通過響應頭Content-Type來確定響應報文類型,但是在早期的瀏覽器中,為了提高用戶體驗,並不會嚴格根據Content-Type的值來解析相應報文,當Content-Type的值缺失,或者瀏覽器認為服務器給出了錯誤的Content-Type值,此時就會對相應報文進行自我解析,即自動判斷報文類型然后進行解析,在這個過程中就有可能觸發XSS攻擊。
X-Content-Type-Options響應頭相當於一個提示標志,被服務器用來提示客戶端一定要遵循在Content-Type中對MIME類型的設定,而不能對其進行修改,這就禁用了客戶端的MIME類型嗅探行為,換言之,就是服務端告訴客戶端其對於MIME類型的設置沒有任何問題。
如果開發者不想禁用MIME嗅探,可以通過以下方式從響應頭中移除X-Content-Type-Options
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.contentTypeOptions()
.disable()
}
Strict-Transport-Security
Strict-Transport-Security用來指定當前客戶端只能通過HTTPS訪問服務器,而不能通過HTTP訪問
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
(1)max-age:設置在瀏覽器收到這個請求后的多少秒時間內,凡是訪問這個域名下到的請求都使用HTTPS請求。
(2)includeSubDomains:這個參數是可選的,如果被指定,表示第一條規則也適用於子域名
這個響應頭並非總是會添加,如果當前請求是HTTPS請求,這個請求頭才會添加,否則該請求頭就不會添加。
如果學要對Strict-Transport-Security的值進行具體配置,方式如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http .headers()
.httpStrictTransportSecurity()
.includeSubDomains(false)
.maxAgeInSeconds(3600);
}
也可以直接調用.disable()方法移除該響應頭
X-Frame-Options
X-Frame-Options響應頭用來告訴瀏覽器是否允許一個頁面在<frame>,<iframe>,<embed>或者<object>中展現,通過該響應頭可以確保網站沒有被嵌入到其他站點中,進而避免發生打擊劫持
X-Frame-Options有三種不同的取值
(1)deny:表示該頁面不允許在frame中展示,即便是在相同域名的頁面中嵌套也不允許。
(2)sameorign:表示該頁面可以在相同域名頁面的frrame中展示
(3)allow-from uri:表示該頁面可以再指定來源的frame中展示
Spring Security默認取值是deny,開發者也可以對此進行修改
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.frameOptions()
.sameOrigin()
}
也可以直接調用.disable()方法移除該響應頭
X-XSS-Protection
X-XSS-Protection響應頭告訴瀏覽器,當檢測到跨站腳本攻擊(XSS)時,瀏覽器將停止加載頁面,該響應頭有四種不同的取值
(1)0表示禁止XSS過濾
(2)1表示啟用XSS過濾(通常瀏覽器是默認的)。如果檢測到跨站腳本攻擊,瀏覽器將清除頁面(刪除不安全的部分)
(3)1;mode=block 表示啟用XSS過濾,如果檢測到攻擊,瀏覽器將不會清除頁面,而阻止頁面加載
(4)1;report=
Spring Security默認設置的是1;mode=block
當然開發者也可以自己配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.xssProtection()
.block(false);
}