對於Web應用程式開發者而言,無論前端或後端,多少都要認識HTTP,而在HTTP的相關知識中,最為人知曉、卻也最被人忽略的是標頭(Header),舉例來說,伺服端的回應標頭,除了控制瀏覽器對內容類型、快取、編碼的處理,也可用來控制現代瀏覽器上安全措施應有之行為。

HTTP安全標頭

談到HTTP標頭的同時又要涉及安全議題之際,Web應用程式開發者可以聯想到的標頭有幾個呢?至少都會聯想到Set-Cookie,因為其中可以附加HttpOnly及secure,前者控制Cookie只能用在HTTP傳輸上,從而限制了JavaScript無法讀取Cookie,這可以用來避免會話劫持(Session hijacking);後者要求Cookie只在加密連線請求時才能發送給瀏覽器。實際上,這在現代瀏覽器中更為嚴格,例如Chrome 52後,非加密連線(非https://)請求下,瀏覽器不會接受secure的Cookie設置。

對於曾經處理跨域請求的開發者來說,應該也接觸過CORS規範,伺服端可以藉由Access-Control-Allow-Origin等標頭,控制瀏覽器是否允許指令稿拿到相關回應,另外,也可使用Vary來控制瀏覽器對相同URL資源的快取行為,這在先前專欄〈深入認識跨域請求〉探討過。

然而,試著用瀏覽器開啟「Security Headers」這個網站,輸入網站網域名稱後、按下「Scan」,你是否會得到大紅的「F」?Security Headers會檢測指定的網址,是否傳回預期的7個安全有關的回應標頭及其設定內容,從而決定出網站的安全指數。

實際上,與安全相關的回應標頭不只7個,還有OWASP的Secure Headers Project,當中也列出了安全相關的標頭,若要了解各瀏覽器在哪個版本實現、各大網站採用的現況、相關的增刪變更,以及可用的檢測工具等資訊,在它的「Best Practices」中,也列出了這些安全標頭的相關說明。

控制瀏覽器的安全措施

現代瀏覽器如Chrome、Firefox、Safari甚至是IE,都實作了一組可被HTTP回應標頭控制的安全措施。因此,在沒有進一步被相關標頭指示下,這些安全措施會有預設行為,然而Web開發人員或網站管理者,還是可以藉由標頭來改變其行為。

以XSS的防護為例,現代瀏覽器在檢測到發出的請求與得到的回應中,若包含了相同的(惡意)指令稿,預設就會封鎖指令稿執行並不顯示頁面內容,X-XSS-Protection標頭可用來控制是否關閉該功能(0為關閉)、過濾指令稿後是否顯示內容(1; mode=block是封鎖)、或者回報至指定網址(1;report=your-url),當然,這主要是針對反射式XSS的預防。

其中的X-Frame-Options可用來控制瀏覽器,可否在iframe裡顯示網站內容(DENY、SAMEORIGIN或者用ALLOW-FROM設置白名單)。但這不是為了避免自家內容被其他的網站蓋臺顯示,主要是用來避免介面偽照(UI Redressing)的相關攻擊,像是在近乎透明的iframe中載入惡意網站,實現點擊劫持(ClickJacking)或提取使用者輸入內容等攻擊。

若伺服器回應時沒有指定Content-Type,瀏覽器會試著嗅探(Sniff)回應類型,並進行探測到的類型應有行為。如果惡意偽裝為圖片連結,內容實際上卻是指令稿,在沒有指定Content-Type的情況下,瀏覽器就有可能執行指令稿,為了避免這類問題,X-Content-Type-Options可設置為nosniff,不過要注意,雖然字面上是用來關閉瀏覽器的嗅探行為,然而因為相容性的問題(https://bit.ly/2WCB5nK),實際上只會套用在script與style,要求這兩者必須在有正確的內容類型指定下,才能運作。

另一個是Referer標頭(在規範中被拼錯),可用來表示請求是從哪個頁面連結而來,對於網站做些來源統計。然而,有時這裡會意外地洩漏敏感訊息,像是附在網站上的會話ID等,可運用Referrer-Policy的8個設定值,規範在是否同源、加密連線等的情況下,瀏覽器才附上Referer標頭,當然也可設定no-referrer,來完全關閉Referer標頭之使用。

接下來,是Strict-Transport-Security的標頭,可用來強制要求瀏覽器,就算一開始是http://,接下來的設定期間內(max-age,以秒為單位),瀏覽器都要使用加密連線,執行相關設定時,可決定是否包含子域(includeSubDomains);Feature-Policy是個相對比較新的標頭,控制的是瀏覽器的特性,可用來決定瀏覽器是否可使用某些API或設備(例如相機頭),Chrome在60版之後才加入此支援。

內容安全策略

Content-Security-Policy是設定最多樣、最繁複,也值得特別討論的安全標頭。先前談過的X-XSS-Protection,主要是針對反射式XSS的預防,對於其他類型的XSS,往往有賴於Web應用程式在實作上加以防堵。基本上,Content Security Policy(CSP)是2010年被提出來討論的規範,其目的在於,從根本禁止瀏覽器從非預期的來源,載入惡意指令稿。

CSP規範在提出討論之後,接下來在發展的過程中,各家瀏覽器就在試著實現了,因此這中間除了Content-Security-Policy之外,還出現了X-Content-Security-Policy、X-WebKit-CSP等非標準標頭。而CSP的版本,在2015年1.0版正式釋出,2016年來到2.0版,目前3.0版正在草案階段。

XSS的問題,根本上是瀏覽器不知道哪些來源的資源是可信任的,CSP簡單來說就是設置白名單,明確告知瀏覽器,只能夠從哪個來源載入資源,可控制的資源包括:script、style、img、media、object、frame、font等,我們在default-src裡面,可以設定預設值,例如若沒有設定script-src的名單,那就看default-src中的名單,確定可否載入指令稿,對於不在白名單的載入行為,report-uri可用來要求瀏覽器發送報告至指定網址。

然而,使用白名單設置是個麻煩的過程。由於現代Web應用程式,往往會從多個來源(CDN之類)載入資源,過於嚴格的白名單,甚至會造成網站來源間的設置衝突。

為此,CSP也有一些寬鬆的設定選項(像是unsafe-inline等),不過往往也被濫用,若沒有正確地設置這類選項,相關規則就會被繞過,而無法有效防範XSS,在網站上搜尋「CSP bypass」就可以找到大量的案例。為了協助運用CSP防堵XSS,也為了能正確地、安全地設置CSP選項,Google推出了CSP Evaluator(https://csp-evaluator.withgoogle.com/),可以把編寫好的CSP貼上去,以檢測內容是否正確,以及是否有安全問題,也可以看看其中的「Sample unsafe policy」,因為,這看似設定得很用心的CSP範例,其實問題多多。

被動防守與主動防堵

各類型HTTP伺服器,都有方式可以全域設置這些安全性標頭,有些Web框架也提供相關設定,各個安全標頭的作用與設定細節,只要在網路搜尋「HTTP Header Security」,都能找到說明,因此,重點應擺在認識這些文件背後著墨的安全議題。

Web應用程式過去在安全性這方面,往往只能被動地等待瀏覽器的請求,看看是否有需要防堵的攻擊,甚至連使用者被攻擊了都不知道(像是DOM-based XSS);而HTTP安全相關的標頭,可以主動地要求瀏覽器,積極地遵守標頭的指示,不發起非安全的操作,若能善加利用,對Web應用程式的安全性,也會是不小的助益。

作者簡介


Advertisement

更多 iThome相關內容