天天看點

[譯] 如何使用 HTTP Headers 來保護你的 Web 應用

<b></b>

<b>文講的是[譯] 如何使用 HTTP Headers 來保護你的 Web 應用,</b>

開發者可以利用 HTTP 響應頭來加強 Web 應用程式的安全性,通常隻需要添加幾行代碼即可。本文将介紹 web 開發者如何利用 HTTP Headers 來建構安全的應用。雖然本文的示例代碼是 Node.js,但基本所有主流的服務端語言都支援設定 HTTP 響應頭,并且都可以簡單地對其進行配置。

技術上來說,HTTP 頭隻是簡單的字段,以明文形式編碼,它是 HTTP 請求和響應消息頭的一部分。它們旨在使用戶端和服務端都能夠發送和接受有關要建立的連接配接、所請求的資源,以及傳回的資源本身的中繼資料。

可以簡單地使用 cURL <code>--head</code> 來檢查純文字 HTTP 響應頭,例如:

緩存是優化用戶端-服務端架構性能中有效的技術,HTTP 也不例外,同樣廣泛利用了緩存技術。但是,在緩存的資源是保密的情況下,緩存可能導緻漏洞,是以必須避免。假設一個 web 應用對含有敏感資訊的網頁進行緩存,并且是在一台公用的 PC 上使用,任何人可以通過通路浏覽器的緩存看到這個 web 應用上的敏感資訊,甚至有時僅僅通過點選浏覽器的傳回按鈕就可以看到。

當你準備傳回敏感資訊并希望禁用 HTTP 用戶端的緩存時,有三個響應頭可以傳回:

<code>Cache-Control</code>

從 HTTP 1.1 引入的此響應頭可能包含一個或多個指令,每個指令帶有特定的緩存語義,訓示 HTTP 用戶端和代理如何處理有此響應頭注釋的響應。我推薦如下指定響應頭,<code>cache-control: no-cache, no-store, must-revalidate</code>。這三個指令基本上可以訓示用戶端和中間代理不可使用之前緩存的響應,不可存儲響應,甚至就算響應被緩存,也必須從源伺服器上重新驗證。

<code>Pragma: no-cache</code>

為了向後相容 HTTP 1.0,你還需要包含此響應頭。有部分用戶端,特别是中間代理,可能仍然沒有完全支援 HTTP 1.1,是以不能正确處理前面提到的 <code>Cache-Control</code> 響應頭,是以使用<code>Pragma: no-cache</code> 確定較舊的用戶端不緩存你的響應。

<code>Expires: -1</code>

此響應頭指定了該響應過期的時間戳。如果不指定為未來某個真實時間而指定為 <code>-1</code>,可以保證用戶端立即将此響應視為過期并避免緩存。

下面是 Node.js 中設定響應頭的示例代碼:

今天,HTTPS 的重要性已經得到了技術界的廣泛認可。越來越多的 web 應用配置了安全端點,并将不安全網路重定向到安全端點(即 HTTP 重定向至 HTTPS)。不幸的是,終端使用者還未完全了解 HTTPS 的重要性,這種缺乏了解使他們面臨着各種中間人攻擊(MitM)。普通使用者通路到一個 web 應用時,并不會注意到正在使用的網絡協定是安全的(HTTPS)還是不安全的(HTTP)。甚至,當浏覽器出現了證書錯誤或警告時,很多使用者會直接點選略過警告。

與 web 應用進行互動時,通過有效的 HTTPS 連接配接是非常重要的:不安全的連接配接将會使得使用者暴露在各種攻擊之下,這可能導緻 cookie 被盜甚至更糟。舉個例子,攻擊者可以在公共 Wi-Fi 網絡下輕易騙取網絡幀并提取那些不使用 HTTPS 的使用者的會話 cookie。更糟的情況是,即使使用者通過安全連接配接與 web 應用進行互動也可能遭受降級攻擊,這種攻擊試圖強制将連接配接降級到不安全的連接配接,進而使使用者受到中間人攻擊。

HSTS 的指令如下:

<code>max-age=&lt;number of seconds&gt;</code>

此項訓示浏覽器對此域緩存此響應頭指定的秒數。這樣可以保證長時間的加強安全。

<code>includeSubDomains</code>

此項訓示浏覽器對目前域的所有子域應用 HSTS,這可以用于所有目前和未來可能的子域。

<code>preload</code>

注意謹慎使用 <code>preload</code>,因為這意味着它不能輕易撤銷,并可能更新延遲數個月。雖然預加載肯定會加強應用程式的安全性,但也意味着你需要充分确信你的應用程式僅支援 HTTPS!

我建議的用法是 <code>Strict-Transport-Security: max-age=31536000; includeSubDomains;</code>,這樣訓示了浏覽器強制通過 HTTPS 連接配接到源主機并且有效期為一年。如果你對你的 app 僅處理 HTTPS 很有信心,我也推薦加上 <code>preload</code> 指令,當然别忘記去前面提到的預加載清單注冊你的網站。

以下是在 Nodes.js 中實作 HSTS 的方法:

在反射型跨站腳本攻擊(reflected XSS)中,攻擊者将惡意 JavaScript 代碼注入到 HTTP 請求,注入的代碼「映射」到響應中,并由浏覽器執行,進而使惡意代碼在可信任的上下文中執行,通路諸如會話 cookie 中的潛在機密資訊。不幸的是,XSS 是一個很常見的網絡應用攻擊,且令人驚訝地有效!

為了了解反射型 XSS 攻擊,參考以下 Node.js 代碼,渲染 <code>mywebapp.com</code>,模拟一個簡單的 web 應用程式,它将搜尋結果以及使用者請求的搜尋關鍵詞一起呈現:

現在,來考慮一下上面的 web 應用程式會如何處理在 URL 中嵌入的惡意可執行代碼,例如:

你可能意識到了,這個 URL 會讓浏覽器執行注入的腳本,并發送極有可能包含機密會話的使用者 cookies 到 evil.com。

為了保護使用者抵抗反射型 XSS 攻擊,有些浏覽器實施了保護機制。這些保護機制嘗試通過在 HTTP 請求和響應中尋找比對的代碼模式來辨識這些攻擊。Internet Explorer 是第一個推出這種機制的,在 2008 年的 IE 8 中引入了 XSS 過濾器的機制,而 WebKit 後來推出了 XSS 審計,現今在 Chrome 和 Safari 上可用(Firefox 沒有内置類似的機制,但是使用者可以使用插件來獲得此功能)。這些保護機制并不完美,它們可能無法檢測到真正的 XSS 攻擊(漏報),在其他情況可能會阻止合法代碼(誤判)。由于後一種情況的出現,浏覽器允許使用者可設定禁用 XSS 過濾功能。不幸的是,這通常是一個全局設定,這會完全關閉所有浏覽器加載的 web 應用程式的安全功能。

幸運的是,有方法可以讓 web 應用覆寫此配置,并確定浏覽器加載的 web 應用已打開 XSS 過濾器。即通過設定 <code>X-XSS-Protection</code> 響應頭實作。此響應頭支援 Internet Explorer(IE8 以上)、Edge、Chrome 和 Safari,訓示浏覽器打開或關閉内置的保護機制,及覆寫浏覽器的本地配置。

<code>X-XSS-Protection</code> 指令包括:

<code>1</code> 或者 <code>0</code>

使用或禁用 XSS 過濾器。

<code>mode=block</code>

當檢測到 XSS 攻擊時,這會訓示浏覽器不渲染整個頁面。

我建議永遠打開 XSS 過濾器以及 block 模式,以求最大化保護使用者。這樣的響應頭應該是這樣的:

以下是在 Node.js 中配置此響應頭的方法:

iframe (正式來說,是 HTML 内聯架構元素)是一個 DOM 元素,它允許一個 web 應用嵌套在另一個 web 應用中。這個強大的元素有部分重要的使用場景,比如在 web 應用中嵌入第三方内容,但它也有重大的缺點,例如對 SEO 不友好,對浏覽器導航跳轉也不友好等等。

其中一個需要注意的事是它使得點選劫持變得更加容易。點選劫持是一種誘使使用者點選并非他們想要點選的目标的攻擊。要了解一個簡單的劫持實作,參考以下 HTML,當使用者認為他們點選可以獲得獎品時,實際上是試圖欺騙使用者購買面包機。

有許多惡意應用程式都采用了點選劫持,例如誘導使用者點贊,線上購買商品,甚至送出機密資訊。惡意 web 應用程式可以通過在其惡意應用中嵌入合法的 web 應用來利用 iframe 進行點選劫持,這可以通過設定 <code>opacity: 0</code> 的 CSS 規則将其隐藏,并将 iframe 的點選目标直接放置在看起來無辜的按鈕之上。點選了這個無害按鈕的使用者會直接點選在嵌入的 web 應用上,并不知道點選後的後果。

我的建議是使用 <code>SAMEORIGIN</code> 指令,因為它允許 iframe 被同域的應用程式所使用,這有時是有用的。以下是響應頭的示例:

以下是在 Node.js 中設定此響應頭的示例代碼:

如前所述,你可以通過啟用浏覽器的 XSS 過濾器,給你的 web 應用程式增強安全性。然而請注意,這種機制是有局限性的,不是所有浏覽器都支援(例如 Firefox 就不支援 XSS 過濾),并且依賴的模式比對技術可以被欺騙。

對抗 XSS 和其他攻擊的另一層的保護,可以通過明确列出可信來源和操作來實作 —— 這就是内容安全政策(CSP)。

CSP 是一種 W3C 規範,它定義了強大的基于浏覽器的安全機制,可以對 web 應用中的資源加載以及腳本執行進行精細的控制。使用 CSP 可以将特定的域加入白名單進行腳本加載、AJAX 調用、圖像加載和樣式加載等操作。你可以啟用或禁用内聯腳本或動态腳本(臭名昭著的 <code>eval</code>),并通過将特定域列入白名單來控制架構化。CSP 的另一個很酷的功能是它允許配置實時報告目标,以便實時監控應用程式進行 CSP 阻止操作。

這種對資源加載和腳本執行的明确的白名單提供了很強的安全性,在很多情況下都可以防範攻擊。例如,使用 CSP 禁止内聯腳本,你可以防範很多反射型 XSS 攻擊,因為它們依賴于将内聯腳本注入到 DOM。

以下是一個設定 CSP 的示例代碼,它僅允許從應用程式的源域加載腳本,并阻止動态腳本的執行(eval)以及内嵌腳本(當然,還是 Node.js):

為了使使用者體驗盡可能無縫,許多浏覽器實作了一個功能叫内容類型嗅探,或者 MIME 嗅探。這個功能使得浏覽器可以通過「嗅探」實際 HTTP 響應的資源的内容直接檢測到資源的類型,無視響應頭中 <code>Content-Type</code> 指定的資源類型。雖然這個功能在某些情況下确實是有用的,它引入了一個漏洞以及一種叫 MIME 類型混淆攻擊的攻擊手法。MIME 嗅探漏洞使攻擊者可以注入惡意資源,例如惡意腳本,僞裝成一個無害的資源,例如一張圖檔。通過 MIME 嗅探,浏覽器将忽略聲明的圖像内容類型,它不會渲染圖檔,而是執行惡意腳本。

<code>X-Content-Type-Options</code> 是一個很簡單的響應頭,它隻有一個指令,<code>nosniff</code>。它是這樣指定的:<code>X-Content-Type-Options: nosniff</code>。以下是示例代碼:

本文中,我們了解了如何利用 HTTP 響應頭來加強 web 應用的安全性,防止攻擊和減輕漏洞。

<b>原文釋出時間為:2017年4月18日</b>

<b>本文來自雲栖社群合作夥伴掘金,了解相關資訊可以關注掘金網站。</b>

繼續閱讀