0x00 背景
在統計了Alexa top 100萬網站的header安全分析之后(2012年11月 - 2013年3月 - 2013年11月),我們發現其實如何正確的設置一個header并不是一件容易的事情。盡管有數不勝數的網站會使用大量有關安全方面的header,但 并沒有一個像樣的平臺能夠為開發者們提供必要的信息,以辨別那些常見的錯誤設置。或者說,即使這些安全方面的header設置正確了,也沒有一個平臺能夠 為開發者提供一個系統的測試方法,用來測試正確與否。這些header如果設置錯誤了不僅會產生安全的假象,甚至會對網站的安全產生威脅。 veracode認為安全性header是網絡防護中非常重要的一環,并且他希望讓開發者們能夠簡捷、正確地設置站點。如果您對某一header或設置有 任何疑問,我們有極好的資源能夠追蹤到瀏覽器支持情況。
0x01 細節
1. X-XSS-Protection
目的
這個header主要是用來防止瀏覽器中的反射性xss。現在,只有IE,chrome和safari(webkit)支持這個header。
正確的設置
0 – 關閉對瀏覽器的xss防護 1 – 開啟xss防護 1; mode=block – 開啟xss防護并通知瀏覽器阻止而不是過濾用戶注入的腳本。 1; report=http://site.com/report – 這個只有chrome和webkit內核的瀏覽器支持,這種模式告訴瀏覽器當發現疑似xss攻擊的時候就將這部分數據post到指定地址。
通常不正確的設置
0; mode=block; – 記住當配置為0的時候,即使加了mode=block選項也是沒有效果的。需要指出的是,chrome在發現這種錯誤的配置后還是會開啟xss防護。 1 mode=block; – 數字和選項之間必須是用分號分割,逗號和空格都是錯誤的。但是這種錯誤配置情況下,IE和chrome還是默認會清洗xss攻擊,但是不會阻攔。
如何檢測
如果過濾器檢測或阻攔了一個反射性xss以后,IE會彈出一個對話框。當設置為1時,chrome會隱藏對反射性xss的輸出。如果是設置為 1; mode=block ,那么chrome會直接將user-agent置為一個空值:, URL ?這種形式。
參考文獻
Post from Microsoft on the X-XSS-Protection Header
Chromium X-XSS-Protection Header Parsing Source
Discussion of report format in WebKit bugzilla
2. X-Content-Type-Options
目的
這個header主要用來防止在IE9、chrome和safari中的MIME類型混淆攻擊。firefox目前對此還存在爭議。通常瀏覽器可以 通過嗅探內容本身的方法來決定它是什么類型,而不是看響應中的content-type值。通過設置 X-Content-Type-Options:如果content-type和期望的類型匹配,則不需要嗅探,只能從外部加載確定類型的資源。舉個例 子,如果加載了一個樣式表,那么資源的MIME類型只能是text/css,對于IE中的腳本資源,以下的內容類型是有效的:
application/ecmascript application/javascript application/x-javascript text/ecmascript text/javascript text/jscript text/x-javascript text/vbs text/vbscript
對于chrome,則支持下面的MIME 類型:
text/javascript text/ecmascript application/javascript application/ecmascript application/x-javascript text/javascript1.1 text/javascript1.2 text/javascript1.3 text/jscript text/live script
正確的設置
nosniff – 這個是唯一正確的設置,必須這樣。
通常不正確的設置
‘nosniff’ – 引號是不允許的 : nosniff – 冒號也是錯誤的?
如何檢測
在IE和chrome中打開開發者工具,在控制臺中觀察配置了nosniff和沒有配置nosniff的輸出有啥區別。
參考文獻
Microsoft Post on Reducing MIME type security risks
Chromium Source for parsing nosniff from response
Chromium Source list of JS MIME types
MIME Sniffing Living Standard
3. X-Frame-Options
目的
這個header主要用來配置哪些網站可以通過frame來加載資源。它主要是用來防止UI redressing 補償樣式攻擊。IE8和firefox 18以后的版本都開始支持ALLOW-FROM。chrome和safari都不支持ALLOW-FROM,但是WebKit已經在研究這個了。
正確的設置
DENY – 禁止所有的資源(本地或遠程)試圖通過frame來加載其他也支持X-Frame-Options 的資源。 SAMEORIGIN – 只允許遵守同源策略的資源(和站點同源)通過frame加載那些受保護的資源。 ALLOW-FROM http://www.example.com – 允許指定的資源(必須帶上協議http或者https)通過frame來加載受保護的資源。這個配置只在IE和firefox下面有效。其他瀏覽器則默認允許任何源的資源(在X-Frame-Options沒設置的情況下)。
通常不正確的設置
ALLOW FROM http://example.com – ALLOW和FROM 之間只能通過連字符來連接,空格是錯誤的。 ALLOW-FROM example.com – ALLOW-FROM選項后面必須跟上一個URI而且要有明確的協議(http或者https)
如何檢測
可以通過訪問test cases 來查看各種各樣的選項 和瀏覽器對這些frame中的資源的響應。
參考文獻
X-Frame-Options RFC
Combating ClickJacking With X-Frame-Options
4. Strict-Transport-Security
目的
Strict Transport Security (STS) 是用來配置瀏覽器和服務器之間安全的通信。它主要是用來防止中間人攻擊,因為它強制所有的通信都走TLS。目前IE還不支持 STS頭。需要注意的是,在普通的http請求中配置STS是沒有作用的,因為攻擊者很容易就能更改這些值。為了防止這樣的現象發生,很多瀏覽器內置了一 個配置了STS的站點list。
?
正確的設置 ?
注意下面的值必須在https中才有效,如果是在http中配置會沒有效果。
?
max-age=31536000 – 告訴瀏覽器將域名緩存到STS list里面,時間是一年。 max-age=31536000; includeSubDomains – 告訴瀏覽器將域名緩存到STS list里面并且包含所有的子域名,時間是一年。 max-age=0 – 告訴瀏覽器移除在STS緩存里的域名,或者不保存此域名。
通常不正確的設置
直接將includeSubDomains設置為 https://www.example.com ,但是用戶依然可以通過 http://example.com 來訪問此站點。如果example.com 并沒有跳轉到 https://example.com 并設置 STS header,那么訪問 http://www.example.com 就會直接被瀏覽器重定向到 https://www.example.com 。 max-age=60 – 這個只設置域名保存時間為60秒。這個時間太短了,可能并不能很好的保護用戶,可以嘗試先通過http來訪問站點,這樣可以縮短傳輸時間。 max-age=31536000 includeSubDomains – max-age 和 includeSubDomains 直接必須用分號分割。這種情況下,即使max-age的值設置的沒有問題,chrome也不會將此站點保存到STS緩存中。 max-age=31536000, includeSubDomains – 同上面情況一樣。 max-age=0 – 盡管這樣在技術上是沒有問題的,但是很多站點可能在處理起來會出差錯,因為0可能意味著永遠不過期。
如何檢測
判斷一個主機是否在你的STS緩存中,chrome可以通過訪問chrome://net-internals/#hsts,首先,通過域名請求選 項來確認此域名是否在你的STS緩存中。然后,通過https訪問這個網站,嘗試再次請求返回的STS頭,來決定是否添加正確。
參考文獻
Strict Transport Security RFC6797
Wikipedia page on Strict Transport Security (with examples)
5. Public-Key-Pins (起草中)
目的
有關這個header的詳細描述還在起草中,但是它已經有了很清晰的安全作用,所以我還是把它放在了這個list里面。Public-Key- Pins (PKP)的目的主要是允許網站經營者提供一個哈希過的公共密鑰存儲在用戶的瀏覽器緩存里。跟Strict-Transport-Security功能相 似的是,它能保護用戶免遭中間人攻擊。這個header可能包含多層的哈希運算,比如pin-sha256=base64(sha256(SPKI)), 具體是先將 X.509 證書下的Subject Public Key Info (SPKI) 做sha256哈希運算,然后再做base64編碼。然而,這些規定有可能更改,例如有人指出,在引號中封裝哈希是無效的,而且在33版本的chrome 中也不會保存pkp的哈希到緩存中。
這個header和 STS的作用很像,因為它規定了最大子域名的數量。此外,pkp還提供了一個Public-Key-Pins-Report-Only 頭用來報告異常,但是不會強制阻塞證書信息。當然,這些chrome都是不支持的。
正確的設置
max-age=3000; pin-sha256=”d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=”; – 規定此站點有3000秒的時間來對x.509證書項目中的公共密鑰信息(引號里面的內容)做sha256哈希運算再做base64編碼。 max-age=3000; pin-sha256=”d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=”; report-uri=”http://example.com/pkp-report” – 同上面一樣,區別是可以報告異常。
通常不正確的設置
max-age=3000; pin-sha256=d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=; – Not encapsulating the hash value in quotes leads to Chrome 33 not adding the keys to the PKP cache. This mistake was observed in all but one of the four sites that returned this or the report-only header response.沒有添加引號,這樣的話chrome不會將這個key添加到PKP緩存中。我們的調查中發現有四分之一的網站存在此問題。
如何檢測
如果站點成功的將pkp哈希存入了客戶端緩存,那么使用和Strict-Transport-Security (STS)相同的方法查看pubkey_hashes 信息就可以了。
參考文獻
Public-Key-Pins draft specification
Chrome issue tracking the implementation of Public-Key-Pins
Chromium source code for processing Public-Key-Pins header
6. Access-Control-Allow-Origin
目的
Access-Control-Allow-Origin是從Cross Origin Resource Sharing (CORS)中分離出來的。這個header是決定哪些網站可以訪問資源,通過定義一個通配符來決定是單一的網站還是所有網站可以訪問我們的資源。需要注 意的是,如果定義了通配符,那么 Access-Control-Allow-Credentials選項就無效了,而且user-agent的cookies不會在請求里發送。
正確的設置
* – 通配符允許任何遠程資源來訪問含有Access-Control-Allow-Origin 的內容。 http://www.example.com – 只允許特定站點才能訪問(http://[host], 或者 https://[host])
通常不正確的設置
http://example.com, http://web2.example.com – 多個站點是不支持的,只能配置一個站點。 *.example.com – 只允許單一的站點 http://*.example.com – 同上面一樣
如何檢測
很容易就能確定這個header是否被設置的正確,因為如果設置錯誤的話,CORS請求就會接收不到數據。
參考文獻
W3C CORS specification
Content-Security-Policy 1.0
目的
csp是一些指令的集合,可以用來限制頁面加載各種各樣的資源。目前,IE瀏覽器只支持CSP的一部分,而且僅支持X-Content- Security-Policy header。 相比較而言,Chrome和Firefox則支持CSP的1.0版本,csp的1.1版本則還在開發中。通過恰當的配置csp,可以防止站點遭受很多類型 的攻擊,譬如xss和UI補償等相關問題。
csp總共有10種配置形式,每一種都可以用來限制站點何時加載和加載何種類型的資源。他們分別是:
default-src:這種形式默認設置為 script-src, object-src, style-src, img-src, media-src, frame-src, font-src和connect-src.如果上述設置一個都沒有的話,user-agent就會被用來作為default-src的值。
script-src:這種形式也有兩個附加的設置。
1、unsafe-inline:允許資源執行腳本。舉個例子,on事件的值會被編碼到html代碼中,或者腳本元素的text的內容會被混入到受保護的資源中。 2、unsafe-eval:允許資源動態的執行函數,比如eval,setTimeout, setInterval, new等函數。
object-src – 決定從哪里加載和執行插件。
style-src – 決定從哪里加載css和樣式標記。
img-src – 決定從哪里加載圖片。
media-src – 決定從哪里加載視頻和音頻資源。
frame-src – 決定哪里的frames 可以被嵌入。
font-src – 決定從哪里加載字體。
connect-src – 限制在 XMLHttpRequest, WebSocket 和 EventSource 中可以使用哪些類型的資源。
sandbox – 這是一個可選形式,它決定了沙盒的策略,如何將內容嵌入到沙盒中以保證安全。
當這個策略被特定的url違反了,我們也可以用報告地址直接發送報告。這樣做有利于debug和當攻擊發生時通知我們。
此外, 我們可以定義Content-Security-Policy-Report-Only 的 header不強制遵守csp,但是會發送潛在的威脅到一個報告地址。它遵守和csp一樣的語法和規則。
正確的設置
View cspplayground.com compliant examples
通常不正確的設置:
View cspplayground.com violation examples
如何檢測
在chrome和firefox中打開開發者工具或者firebug,在控制臺查看是否有潛在的威脅。
參考文獻
Content Security Policy 1.0 Specification
Content Security Policy 1.1 Working Draft Specification
cspplayground.com’s excellent collection of resources for CSP
Sublime Text 2 Plugin for validating HTML/JS while you code your site
關于Alexa排名top 100萬網站的安全header的研究