Nginx配置各種響應頭防止XSS,點選劫持,frame惡意攻擊

men發表於2020-07-27

為什麼要配置HTTP響應頭?

不知道各位有沒有被各類XSS攻擊、點選劫持 (ClickJacking、 frame 惡意引用等等方式騷擾過,百度聯盟被封就有這些攻擊的功勞在裡面。為此一直都在搜尋相關防禦辦法,至今效果都不是很好,最近發現其實各個瀏覽器本身提供了一些安全相關的響應頭,使用這些響應頭一般只需要修改伺服器配置即可,不需要修改程式程式碼,成本很低。至於具體的效果只能是拭目以待了,但是感覺還是有一定的效果的。

而這些HTTP響應頭在我們部署 Nginx 的時候經常會被忽略掉,個人感覺這是一個比較嚴重的“疏忽”,加上還是很有必要的,如果有條件最好是部署一個適合自己站點的X-Content-Security-Policy響應頭。

點選劫持
# 點選劫持(ClickJacking)是一種視覺上的欺騙手段。大概有兩種方式,

# 一是攻擊者使用一個透明的iframe,覆蓋在一個網頁上,然後誘使使用者在該頁面上進行操作,此時使用者將在不知情的情況下點選透明的iframe頁面;

# 二是攻擊者使用一張圖片覆蓋在網頁,遮擋網頁原有位置的含義;

X-Frame-Options響應頭

X-Frame-Options HTTP 響應頭是微軟提出來的一個HTTP響應頭,主要用來給瀏覽器指示允許一個頁面可否在 <frame>, <iframe> 或者 <object> 中展現的標記。網站可以使用此功能,來確保自己網站的內容沒有被嵌到別人的網站中去,也從而避免了點選劫持 (ClickJacking{注1}) 的攻擊。

使用X-Frame-Options有三個值

# DENY
# 表示該頁面不允許在frame中展示,即使在相同域名的頁面中巢狀也不允許

# SAMEORIGIN
# 表示該頁面可以在相同域名頁面的frame中展示

# ALLOW-FROM url
# 表示該頁面可以在指定來源的frame中展示

如果設定為 DENY,不光在別人的網站 frame 嵌入時會無法載入,在同域名頁面中同樣會無法載入。另一方面,如果設定為SAMEORIGIN,那麼頁面就可以在同域名頁面的 frame 中巢狀。

PS:目前發現這個HTTP響應頭會帶來的問題就是百度統計中的“熱點追蹤(頁面點選圖)”功能會失效,這也說明百度統計的“熱點追蹤(頁面點選圖)”使用的是 frame 嵌入引用網頁的形式,這時候大家可以使用 X-Frame-OptionsALLOW-FROM uri來指定百度統計域名為可 frame 嵌入域名即可。具體在Nginx裡可以採用如下的方式新增響應頭

# add_header X-Frame-Options:ALLOW-FROM https://tongji.baidu.com;
# add_header X-Frame-Options:SAMEORIGIN;

X-Content-Type-Options響應頭

網際網路上的資源有各種型別,通常瀏覽器會根據響應頭的Content-Type欄位來分辨它們的型別。例如:text/html代表html文件,image/png是PNG圖片,text/css是CSS樣式文件。然而,有些資源的Content-Type是錯的或者未定義。這時,某些瀏覽器會啟用MIME-sniffing來猜測該資源的型別,解析內容並執行。

例如,我們即使給一個html文件指定Content-Type為text/plain,在IE8-中這個文件依然會被當做html來解析。利用瀏覽器的這個特性,攻擊者甚至可以讓原本應該解析為圖片的請求被解析為JavaScript。在Nginx裡通過下面這個響應頭可以禁用瀏覽器的型別猜測行為:

# X-Content-Type-Options HTTP 訊息頭相當於一個提示標誌,被伺服器用來提示客戶端一定要遵循在 Content-Type 首部中對  MIME 型別 的設定,
# 而不能對其進行修改。這就禁用了客戶端的 MIME 型別嗅探行為,換句話說,也就是意味著網站管理員確定自己的設定沒有問題。

# X-Content-Type-Options響應頭的缺失使得目標URL更易遭受跨站指令碼攻擊。
# add_header X-Content-Type-Options: nosniff;

這個響應頭的值只能是nosniff, 可用於IE8+和Chrome

IE的行為受X-Content-Type-Options的影響,如果Web應用沒有返回Content-Type,那麼IE9、IE11將拒絕載入相關資源。

# 如果伺服器傳送響應頭 “X-Content-Type-Options: nosniff”,則 script 和 styleSheet
# 元素會拒絕包含錯誤的 MIME 型別的響應。這是一種安全功能,有助於防止基於 MIME 型別混淆的攻擊。

X-Content-Security-Policy響應頭

W3C 的 Content Security Policy,簡稱 CSP。顧名思義,這個規範與內容安全有關,主要是用來定義頁面可以載入哪些資源,減少 XSS 的發生。

Chrome 擴充套件已經引入了 CSP,通過 manifest.json 中的 content_security_policy 欄位來定義。一些現代瀏覽器也支援通過響應頭來定義 CSP。下面我們主要介紹如何通過響應頭來使用 CSP,Chrome 擴充套件中 CSP 的使用可以參考 Chrome 官方文件

# HTTP 響應頭Content-Security-Policy允許站點管理者控制使用者代理能夠為指定的頁面載入哪些資源。
# 除了少數例外情況,設定的政策主要涉及指定伺服器的源和指令碼結束點。

# Content-Security-Policy響應頭的缺失使得目標URL更易遭受跨站指令碼攻擊。
瀏覽器相容性
# 早期的 Chrome 是通過 X-WebKit-CSP 響應頭來支援 CSP 的,而 firefox 和 IE 則支援 X-Content-Security-Policy,
# Chrome25 和 Firefox23 開始支援標準的 Content-Security-Policy
如何使用
# 要使用 CSP,只需要服務端輸出類似這樣的響應頭就行了:
Content-Security-Policy: default-src 'self'
  
# default-src 是 CSP 指令,多個指令之間用英文分號分割;'self' 是指令值,多個指令值用英文空格分割。目前,有這些 CSP 指令:
指令 指令值示例 說明
default-src 'self' cnd.a.com 定義針對所有型別(js、image、css、web font,ajax 請求,iframe,多媒體等)資源的預設載入策略,某型別資源如果沒有單獨定義策略,就使用預設的。
script-src 'self' js.a.com 定義針對 JavaScript 的載入策略。
style-src 'self' css.a.com 定義針對樣式的載入策略。
img-src 'self' img.a.com 定義針對圖片的載入策略。
connect-src 'self' 針對 AjaxWebSocket 等請求的載入策略。不允許的情況下,瀏覽器會模擬一個狀態為 400 的響。
font-src font.a.com 針對 WebFont 的載入策略。
object-src 'self' 針對 <object><embed><applet> 等標籤引入的 flash 等外掛的載入策略。
media-src media.a.com 針對 <audio><video> 等標籤引入的 HTML 多媒體的載入策略。
frame-src 'self' 針對 frame 的載入策略。
sandbox allow-forms 對請求的資源啟用 sandbox(類似於 iframe 的 sandbox 屬性)。
report-uri /report-uri 告訴瀏覽器如果請求的資源不被策略允許時,往哪個地址提交日誌資訊。 特別的:如果想讓瀏覽器只彙報日誌,不阻止任何內容,可以改用 Content-Security-Policy-Report-Only 頭。
指令值 指令示例 說明
img-src 允許任何內容。
'none' img-src 'none' 不允許任何內容。
'self' img-src 'self' 允許來自相同來源的內容(相同的協議、域名和埠)。
data: img-src data: 允許 data: 協議(如 base64 編碼的圖片)。
www.a.com img-src img.a.com 允許載入指定域名的資源。
.a.com img-src .a.com 允許載入 a.com 任何子域的資源。
https://img.com img-src https://img.com 允許載入 img.com 的 https 資源(協議需匹配)。
https: img-src https: 允許載入 https 資源。
'unsafe-inline' script-src 'unsafe-inline' 允許載入 inline 資源(例如常見的 style 屬性,onclick,inline js 和 inline css 等等)。
'unsafe-eval' script-src 'unsafe-eval' 允許載入動態 js 程式碼,例如 eval()。

從上面的介紹可以看到,CSP 協議可以控制的內容非常多。而且如果不特別指定 'unsafe-inline' 時,頁面上所有 inline 樣式和指令碼都不會執行;不特別指定 'unsafe-eval',頁面上不允許使用 new Function,setTimeout,eval 等方式執行動態程式碼。在限制了頁面資源來源之後,被 XSS 的風險確實小不少。

當然,僅僅依靠 CSP 來防範 XSS 是遠遠不夠的,不支援全部瀏覽器是它的硬傷。不過,鑑於低廉的開發成本,加上也沒什麼壞處。

StrictTransportSecurity響應頭

什麼是StrictTransportSecurity?

一個網站接受一個HTTP的請求,然後跳轉到HTTPS,使用者可能在開始跳轉前,通過沒有加密的方式和伺服器對話,比如,使用者輸入http://foo.com或者直接foo.com。這樣存在中間人攻擊潛在威脅,跳轉過程可能被惡意網站利用來直接接觸使用者資訊,而不是原來的加密資訊。網站通過HTTP Strict Transport Security通知瀏覽器,這個網站禁止使用HTTP方式載入,瀏覽器應該自動把所有嘗試使用HTTP的請求自動替換為HTTPS請求。

為什麼要開啟

有的網站開啟了https,但為了照顧使用者的使用體驗(因為使用者總是很賴的,一般不會主動鍵入https,而是直接輸入域名, 直接輸入域名訪問,預設就是http訪問)同時也支援http訪問,當使用者http訪問的時候,就會返回給使用者一個302重定向,重定向到https的地址,然後後續的訪問都使用https傳輸,這種通訊模式看起來貌似沒有問題,但細緻分析,就會發現種通訊模式也存在一個風險,那就是這個302重定向可能會被劫持篡改,如果被改成一個惡意的或者釣魚的https站點,然後,你懂得,一旦落入釣魚站點,資料還有安全可言嗎?

對於篡改302的攻擊,建議伺服器開啟HTTP Strict Transport Security功能,這個功能的含義是:

當使用者已經安全的登入開啟過htst功能的網站 (支援hsts功能的站點會在響應頭中插入:Strict-Transport-Security) 之後,支援htst的瀏覽器(比如chrome. firefox)會自動將這個域名加入到HSTS列表,下次即使使用者使用http訪問這個網站,支援htst功能的瀏覽器就會自動傳送https請求(前提是使用者沒有清空快取,如果清空了快取第一次訪問還是明文,後續瀏覽器接收到伺服器響應頭中的Strict-Transport-Security,就會把域名加入到hsts快取中,然後才會在傳送請求前將http內部轉換成https),而不是先傳送http,然後重定向到https,這樣就能避免中途的302重定向URL被篡改。進一步提高通訊的安全性。

上面是我自己的理解,下面是owasp中文站點關於hsts的描述:

HSTS的作用是強制客戶端(如瀏覽器)使用HTTPS與伺服器建立連線。伺服器開啟HSTS的方法是,當客戶端通過HTTPS發出請求時,在伺服器返回的超文字傳輸協議響應頭中包含Strict-Transport-Security欄位。非加密傳輸時設定的HSTS欄位無效。

比如,https://example.com/ 的響應頭含有Strict-Transport-Security: max-age=31536000; includeSubDomains。這意味著兩點:

在接下來的一年(即31536000秒)中,瀏覽器只要向example.com或其子域名傳送HTTP請求時,必須採用HTTPS來發起連線。比如,使用者點選超連結或在位址列輸入 http://www.example.com/ ,瀏覽器應當自動將 http 轉寫成 https,然後直接向 https://www.example.com/ 傳送請求。

在接下來的一年中,如果 example.com 伺服器傳送的TLS證照無效,使用者不能忽略瀏覽器警告繼續訪問網站。

HSTS可以用來抵禦SSL剝離攻擊。SSL剝離攻擊是中間人攻擊的一種,由Moxie Marlinspike於2009年發明。他在當年的黑帽大會上發表的題為“New Tricks For Defeating SSL In Practice”的演講中將這種攻擊方式公開。SSL剝離的實施方法是阻止瀏覽器與伺服器建立HTTPS連線。它的前提是使用者很少直接在位址列輸入https://,使用者總是通過點選連結或3xx重定向,從HTTP頁面進入HTTPS頁面。所以攻擊者可以在使用者訪問HTTP頁面時替換所有https://開頭的連結為http://,達到阻止HTTPS的目的。

HSTS可以很大程度上解決SSL剝離攻擊,因為只要瀏覽器曾經與伺服器建立過一次安全連線,之後瀏覽器會強制使用HTTPS,即使連結被換成了HTTP

另外,如果中間人使用自己的自簽名證照來進行攻擊,瀏覽器會給出警告,但是許多使用者會忽略警告。HSTS解決了這一問題,一旦伺服器傳送了HSTS欄位,使用者將不再允許忽略警告。

0×03. Strict-Transport-Security的一些不足

使用者首次訪問某網站是不受HSTS保護的。這是因為首次訪問時,瀏覽器還未收到HSTS,所以仍有可能通過明文HTTP來訪問。解決這個不足目前有兩種方案,一是瀏覽器預置HSTS域名列表,Google Chrome、Firefox、Internet Explorer和Spartan實現了這一方案。二是將HSTS資訊加入到域名系統記錄中。但這需要保證DNS的安全性,也就是需要部署域名系統安全擴充套件。截至2014年這一方案沒有大規模部署。

由於HSTS會在一定時間後失效(有效期由max-age指定),所以瀏覽器是否強制HSTS策略取決於當前系統時間。部分作業系統經常通過網路時間協議更新系統時間,如Ubuntu每次連線網路時,OS X Lion每隔9分鐘會自動連線時間伺服器。攻擊者可以通過偽造NTP資訊,設定錯誤時間來繞過HSTS。解決方法是認證NTP資訊,或者禁止NTP大幅度增減時間。比如Windows 8每7天更新一次時間,並且要求每次NTP設定的時間與當前時間不得超過15小時

X-XSS-Protection響應頭

顧名思義,這個響應頭是用來防範XSS的。最早我是在介紹IE8的文章裡看到這個,現在主流瀏覽器都支援,並且預設都開啟了XSS保護,用這個header可以關閉它。它有幾種配置:

0:# 禁用XSS保護;
1:# 啟用XSS保護;
1; # mode=block:啟用XSS保護,並在檢查到XSS攻擊時,停止渲染頁面(例如IE8中,檢查到攻擊時,整個頁面會被一個#替換);

# HTTP X-XSS-Protection 響應頭是 Internet Explorer,Chrome 和 Safari 的一個特性,
# 當檢測到跨站指令碼攻擊 (XSS)時,瀏覽器將停止載入頁面。

# X-XSS-Protection響應頭的缺失使得目標URL更易遭受跨站指令碼攻擊。

# 瀏覽器提供的XSS保護機制並不完美,但是開啟後仍然可以提升攻擊難度,總之沒有特別的理由,不要關閉它。
Nginx配置方法如下
# add_header X-Xss-Protection: 1;
# add_header X-Xss-Protection: mod=block;

實際案例

Google+

使用功能了這幾個文字提到的響應頭

# x-content-type-options: nosniff
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block
Twitter
# strict-transport-security: max-age=631138519
# x-frame-options: SAMEORIGIN
# x-xss-protection: 1; mode=block
PayPal
# X-Frame-Options: SAMEORIGIN
# Strict-Transport-Security: max-age=14400
Facebook

配置了詳細的CSP,關閉了XSS保護

strict-transport-security: max-age=60
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 0
content-security-policy: default-src *;script-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline' 'unsafe-eval' https://*.akamaihd.net http://*.akamaihd.net;style-src * 'unsafe-inline';connect-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.spotilocal.com:* https://*.akamaihd.net ws://*.facebook.com:* http://*.akamaihd.net https://fb.scanandcleanlocal.com:*;

相關文章