WEB安全防護相關響應頭(上)

天存資訊發表於2021-06-03

WEB 安全攻防是個龐大的話題,有各種不同角度的探討和實踐。即使只討論防護的物件,也有諸多不同的方向,包括但不限於:WEB 伺服器、資料庫、業務邏輯、敏感資料等等。除了這些我們慣常關注的方面,WEB 安全還有一個重要的元素——網站的使用者

他們通常是完全沒有 IT 知識的普通使用者,網站方可以做點什麼,以增加對這些普通使用者的保護呢?以前較被忽略的步驟是:正確設定頁面的響應頭 (Response Headers) 。這類加入安全相關響應頭的做法,往往是為了保護客戶端/使用者的安全,減少使用者落入黑客的 WEB 陷阱的可能。

這裡我們介紹一些較為常用的,和安全相關的響應頭。當然,WEB 應用應該根據自己的實際情況部署和設定,並非盲目地一股腦地全部招呼上。

一、X-Frame-Options -- 打破框框

從 2008 年開始,研發人員發現一種利用視覺誤導,引誘使用者行為的可能,這種做法後來被命名為點選劫持 (Click Jacking)

攻擊者的通常做法是,在自己的頁面裡通過框架(iframe)的形式,包含一個不屬於它本站的頁面。下面的示例程式碼裡包含的就是 【163 郵箱】的設定頁。而由黑客控制的父級頁面本身可以是任何內容,它通過精確調整自己頁面的內容和 iframe 的座標及大小,再通過 CSS 的 opacity 透明度設定,把使用者內容所在的 iframe 透明度設定為全透明。

以下為示例程式碼:

<style>
   .iframe{opacity: 0.4;}
  body { background: url(./sales.png) no-repeat fixed top;
  }   
</style>
</head>
<body>
<iframe src="https://m.reg.163.com/?email=1/#/email" width="100%" height="600px"  frameBorder="0" class="iframe" scrolling="no"allowtransparency="true">
</iframe>

得到的效果如下圖:

(點選檢視大圖)

請注意我們為了示例效果,特意設定了透明度僅僅為 {opacity:0.4;} ,保持頁面上能隱約看到 163 郵箱的內容。但如果CSS程式碼設定為 {opacity:0;} ,163 郵箱的內容就會消弭於眼前,只留下這張促銷圖片。但訪問者點到相應位置時,依然會觸發對163郵箱的請求。這個就是點選劫持的原理。

早期 WEB 開發者應對這個問題的處理,是用 JavaScript 實現的,一般是判斷當前 window 物件和 parent 物件是否一致,如果不一致,就執行“破框”跳轉。但這個方式並不可靠!因為各種原因,客戶端有可能禁止了 JavaScript 執行或程式碼被繞過,這樣“破框”程式碼就失效了。在人們日益認識到這種攻擊方式的危害性後,為統一解決這個問題,制定網際網路規範的機構出手了,解決方案就是:

RFC7034
「 HTTP Header Field X-Frame-Options 」
https://tools.ietf.org/html/rfc7034

即引入了一個新的 HTTP 響應頭。現在主流常用瀏覽器已全部支援這一響應頭。具有這個響應頭的資源,可以拒絕自己被非法站點的以下標籤引用:

  • iFrame 標籤
  • Frame 標籤
  • Object 標籤
  • Applet 標籤
  • Embed 標籤

這個頭有三種選項,對應如下:

三種選項 具體含義
X-Frame-Options: DENY 完全不能被嵌入到 iframe、frame 等標籤中
X-Frame-Options: SAMEORIGIN 只能被同源頁面嵌入到 iframe 或者 frame 中
X-Frame-Options: ALLOW-FROM https://example.com/ 只能被指定的 URI 嵌入到 iframe 或 frame 中

所以顯然,上面 163 郵箱的頁面,就沒有返回這個響應頭,存在一定的劫持風險。如果加入這個響應頭,我們的模擬頁面,將無法像上圖那樣直接把 163 郵箱的內容嵌進來。

這個響應頭的 弊端

  • 某些早期瀏覽器可能不支援;
  • 對確實需要嵌入很多第三方資源的複雜頁面不適用。

二、X-Content-Type-Options -- IE你別瞎猜猜了

WEB 伺服器返回的資源包括各種,如圖片、HTML 頁面、JavaScript 指令碼、CSS 指令碼、純文字、二進位制檔案等。瀏覽器對資源的解讀和渲染呈現方式,滲透攻擊時有可能被利用。比如一個允許互動的站點,往往允許上傳圖片、mp3 檔案,甚至允許上傳純文字檔案,但往往不允許上傳 JavaScript 指令碼檔案和 HTML 檔案,因為後者藉助 JavaScript 日益強大的功能,能做的壞事實在有點多。

如無意外,伺服器端返回的每個資源的響應頭裡,一般都帶有 content-type 這個響應頭:

HTTP/1.1 200 OK
Content-Length: 3587
Content-Type: image/png
Date: Wed, 20 Mar 2019 09:40:16 GMT
Last-Modified: Tue, 19 Mar 2019 20:01:14 GMT
Server: Microsoft-IIS/7.5

返回的這個 Content-Type 頭,一般是自動的,如伺服器會根據 URL 字尾對應的檔案型別自動選擇;如不是自動的,則可能是程式設計師在程式碼層設定的,兩種情況均有可能。這個響應頭在較為罕見的情況下,也可能缺失,也可能和實際情況不匹配。而比較早期的瀏覽器,尤其是 IE,會出於“好心”,不但在沒有 Content-Type 頭的時候會主動檢測響應的內容,甚至在已有 Content-Type 頭的時候,也會根據返回的資料體內容,判斷裡面有沒有 HTML 程式碼特徵,如果有,返回的內容會直接被認定為 HTML 型別,而不顧實際的 Content-Type 頭的型別設定。

如以下例子:

HTTP/1.1 200 OK 
Content-Length: 108 
Date: Thu, 26 Jun 2008 22:06:28 GMT 
Content-Type: text/plain; 

<html> 
<body bgcolor="#AA0000"> 
This page renders as HTML source code (text) in IE8. 
</body> 
</html>

就會被早期一些的 IE 判定為 HTML 內容,最後以 HTML 方式被渲染呈現出來,儘管伺服器端已經指定 Content-Type:text/plain; —— 這會導致一定的安全隱患。因為很多有互動功能的伺服器,都會允許上傳某些型別的“無害”檔案,如圖片和 mp3 等,如果在上傳的圖片內,巧妙地嵌入一定的 HTML 和 JavaScript 程式碼,最後能被渲染為 HTML 檔案,顯然會打破同源限制,產生安全隱患。

所以從 IE8 某個版本開始引入了 X-Content-Type-Options 這個新的響應頭,如果這個響應頭的值為 nosniff ,中文直譯即「別嗅探」,就是告訴瀏覽器端,不要再主動猜測文件的型別了,以伺服器端返回為準。後來 Chrome 等瀏覽器也支援這個響應頭。

HTTP/1.1 200 OK 
Content-Length: 108 
Date: Thu, 26 Jun 2008 22:06:28 GMT 
Content-Type: text/plain;
X-Content-Type-Options: nosniff

這個響應頭的 弊端

  • 某些早期瀏覽器不支援。

三、HTTP Strict Transport Security (HSTS) -- 不加密不舒服斯基

隨著 WEB 傳遞的敏感資訊越來越多,加密傳輸 HTTPS 也逐漸超越常規 HTTP,正越來越成為網際網路上各大站點的首選傳輸協議。甚至像谷歌公司,從 2018 年中推出的 Chrome 68 版開始,就對所有 HTTP 訪問提示安全警告了。以下引用自谷歌公司的宣告:

過去幾年中,我們一直主張站點採用 HTTPS,以提升其安全性。去年的時候,我們還通過將更大的 HTTP 頁面標記為‘不安全’以幫助使用者。

但通常使用者在瀏覽器裡輸入域名時,都是不帶協議部分的,比如直接輸入 www.tcxa.com.cn ,由瀏覽器補齊前面缺失的協議部分,變成完整的 URL: http://www.tcxa.com.cn 。瀏覽器預設加入的協議,總是 HTTP 的!對那些同時提供 HTTP 和 HTTPS 服務,但希望訪問者優先使用 HTTPS 服務的站點來說,這種處理就不太符合他們的本意了。

為解決這個問題,標準制定機構2012 年又釋出了一份:

RFC 6797
https://tools.ietf.org/html/rfc6797

這套機制就是 HTTP 嚴格傳輸安全響應頭 (HTTP Strict Transport Security,簡稱 HSTS)

這個響應頭裡,最重要的一個引數項叫 max-age (單位為秒)。這個引數指的是,如果你上一次用 HTTPS 訪問過該站點,下次再來訪問,如果兩次訪問的間隔時間沒有超過這個 max-age 的設定,第二次訪問該站點時,瀏覽器就會直接強制以 HTTPS 協議訪問了。這背後的邏輯是,第一次訪問站點的時候,有針對性的攻擊應該還不會發生。重點是防護後續的訪問,所以後續的訪問需要被強制升級為 HTTPS 協議。這個響應頭需要在 HTTPS 流量裡才有效,在 HTTP 流量裡返回這個頭並沒有作用。

以下是站點 https://www.github.com 返回的部分響應頭摘錄——順便一提,前面介紹的 X-Frame-OptionsX-Content-Type-Options 響應頭也都出現在 github 裡:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Encoding: gzip
Server: GitHub.com
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
Expect-CT: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
Transfer-Encoding: chunked
......
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: deny
......

其中 Strict-Transport-Security 響應頭裡, max-age 的值很大,這個 31536000 秒,其實等於 365 天,也就是一整年的時間。意思是除非前後兩次訪問 github 的時間超過一年,否則每次訪問 github,都會被強制使用 HTTPS。 includeSubdomains 選項代表這個策略涵蓋 github 所有的子域名。

還可以手工強制 HSTS。方式是在 Chrome 瀏覽器位址列內,輸入

chrome://net-internals/#hsts

來到如下圖的配置介面:

圖2

在「Add HSTS domain」裡,手工加入需要強制使用 HTTPS 的域名。在「Query HSTS/PKP domain」裡,則可以查詢某個域名對這個響應頭的設定。

這個響應頭的 弊端

  • 某些早期瀏覽器不支援;
  • 如果 HTTPS 站點出現問題,導致無法訪問, max-age 又設得過大,會導致使用者完全無法回退到訪問 HTTP 站點。

四、瀏覽器相容性

這些響應頭基本上都是在客戶端指令碼越來越強大的 Web 2.0 時代之後才出現的,每種瀏覽器對它們的支援也各異,情況非常複雜混亂。所以使用前也需要評估目標人群的瀏覽器使用場景。

各種瀏覽器對這些響應頭的相容性,可以查詢以下站點:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

如我們本篇提到的第一個響應頭 X-Frame-Options 的相容性情況如下:

圖3

可以看到瀏覽器分電腦和手機版,電腦版裡列出了從哪個版本的瀏覽器開始支援這個響應頭,而且幾個不同的選項值也略有差異。

五、這些響應頭打哪兒來的?!

上面的一切看起來都很美好啦,但問題是:這些響應頭難道是憑空出現的嗎? 要怎麼得到它們呢?一般的 WEB 伺服器自身都支援響應頭自定義設定。同時,各種 WEB 開發程式碼也可以通過程式設計的方式,實現更靈活的響應頭返回和設定。WEB 開發程式碼較為複雜,無法囊括,我們大致介紹一下各種 WEB 伺服器對這個功能的支援。

1. APACHE

例如,可以在Apache配置檔案 httpd.conf 中新增以下配置,限制只有同源頁面才可以嵌入iframe:

Headeralways append X-Frame-OptionsSAMEORIGIN

重啟 apache 使其生效。其他的響應頭也同理。關於Apache Header 指令的詳細用法:

http://httpd.apache.org/docs/current/mod/mod_headers.html#header

2. NGINX

例如,可以在 Nginx 配置檔案 nginx.conf 中的「server」上下文內,新增以下配置,限制只有同源頁面才可以嵌入 iframe:

add_header X-Frame-Options"SAMEORIGIN";

圖4

重啟 Nginx 服務使其生效。其他的響應頭也類似同理。關於Nginx add_header 指令的詳細用法:

http://nginx.org/en/docs/http/ngxhttpheaders_module.html

3. IIS

在 WEB 站點對應的 web.config 中新增配置:

<system.webServer>
	<httpProtocol>
	<customHeaders>
		<add name="X-Frame-Options" value="SAMEORIGIN" />**
	</customHeaders>
	</httpProtocol>

   ...

</system.webServer>

如果不習慣改配置檔案,可以使用圖形控制檯,如下選擇網站對應的「HTTP 響應標頭」:

圖5

再根據實際需求,新增所需的響應頭即可:

圖6

(朱筱丹 | 天存資訊)

Ref

  1. M Zalewski - 《Web之困:現代Web應用安全指南》
  2. List of HTTP header fields
  3. ie8 security part vi beta 2 update
  4. fetch Living Standard
  5. HTTP Strict Transport Security
  6. Referrer Policy 介紹

相關文章