Teambition 對於安全問題一直很是關注,前一陣子@嚴清老師鄭重提出必須即時部署 CSP, 而後你們一塊兒認真琢磨了一下,以爲確實是應該在社區中推廣的安全策略,特別是 Teambition 的合做夥伴們=)。下文是嚴清撰寫的實戰經驗,供你們參考。html
最先接觸 CSP 仍是 AngularJS 的 ng-csp 指令,但實際上一直沒有真正理解,直到兩個月前看了 @xisigr 的這篇文章:《瀏覽器安全策略說以內容安全策略CSP》,才發現 CSP 的確是一個出色的 WEB 安全方案。前端
簡而言之,內容安全策略(Content Security Policy,簡稱 CSP)是一種以可信白名單做機制,來限制網站中是否能夠包含某來源的資源。資源類型細分爲 Script、Style、Image、Font、Connect、Media、Object、Frame 等,可分別配置其來源。默認配置下不容許執行內聯腳本和內聯樣式,也禁止執行 eval。node
這裏我以 Teambition 實際部署過程講解 CSP 部署,讓你們有個感性的認識。nginx
CSP 規則講解web
咱們先來看 Teambition 平臺網頁的一段 Response Headers:後端
content-encoding:gzip content-security-policy:default-src https://*.teambition.com; script-src https://dn-st.oss.aliyuncs.com https://hm.baidu.com https://cdn.mxpnl.com https://www.google-analytics.com; style-src data: 'unsafe-inline' https://dn-st.oss.aliyuncs.com; img-src data: blob: https://*.teambition.com https://dn-st.oss.aliyuncs.com https://dn-st.qbox.me https://hm.baidu.com https://www.google-analytics.com; frame-src https:; font-src https://dn-st.oss.aliyuncs.com; connect-src https://*.teambition.com wss://*.teambition.com https://api.mixpanel.com content-type:text/html; charset=utf-8 date:Sat, 02 Aug 2014 10:41:10 GMT server:nginx status:200 OK teambition:wv=release version:HTTP/1.1
其中 content-security-policy 的內容就是咱們設定的 CSP 規則,Response Headers 中還有 x-content-security-policy 和x-webkit-csp,內容同樣,是爲了作瀏覽器兼容。其中的 CSP 規則詳細解釋以下:api
default-src https://*.teambition.com;
default-src 默認規則,當相關資源未定義規則時,就使用默認規則,這裏定義了只容許從 teambition.com 域及子域加載資源,而且必須是 https 安全連接。瀏覽器
script-src https://dn-st.oss.aliyuncs.com https://hm.baidu.com https://cdn.mxpnl.com https://www.google-analytics.com;
script-src JS 腳本規則,這裏只容許從阿里雲、百度、mixpanel、google 的指定域下加載腳本,其中阿里雲是 teambition 使用的 CDN,後三者是由於要加載統計腳本。另外,CSP 規則默認不容許執行內聯 JS 腳本、eval、Function 等。最大程度的限制了非法 JS 腳本的運行。咱們部署 CSP 的主要工做就是去除源碼中的內聯腳本。安全
style-src data: 'unsafe-inline' https://dn-st.oss.aliyuncs.com;
style-src CSS 樣式規則,這裏只容許從阿里雲的指定域下加載 CSS,而且容許 data 和內聯 CSS,CSP 規則默認不容許內聯 CSS,但實際場景中,不少 UI 控制都依賴內聯 CSS,尤爲是網頁動畫。服務器
img-src data: blob: https://*.teambition.com https://dn-st.oss.aliyuncs.com https://dn-st.qbox.me https://hm.baidu.com https://www.google-analytics.com;
img-src img 規則,這裏限制放得比較寬,其中還有百度和 google 的域,是由於他們的統計請求返回的是圖片,若是禁了統計請求將失效。
frame-src https:;
frame-src frame 規則,這裏目前容許全部 https 連接。實際上 teambition 目前只使用了 dropbox 的組件。從此根據狀況再調整。
font-src https://dn-st.oss.aliyuncs.com;
font-src font 規則,一樣只容許從阿里雲加載。
connect-src https://*.teambition.com wss://*.teambition.com https://api.mixpanel.com
connect-src connect 規則,包括 XMLHttpRequest、WebSocket 等連接。teambition 的消息推送就用了 WebSocket 連接。
另外還有 Object、Media 等未定義的就使用 default-src 規則。也還有一些 CSP 特性,如 report-uri 攻擊報告等,這裏再也不闡述。
CSP 後端部署
Teambition 使用的 node.js 服務器,部署至關簡單,相關代碼端以下:
if (config.CSP_HEADER) { res.set({ 'Content-Security-Policy': config.CSP_HEADER, 'X-Content-Security-Policy': config.CSP_HEADER, 'X-WebKit-CSP': config.CSP_HEADER }); }
也就是判斷 CSP 規則是否存在,存在就將其設置到網頁頭部。這裏之因此有這個判斷,是由於 teambition 存在開發環境、測試環境、線上環境和私有部署環境,不一樣環境配置了不一樣規則。
CSP 部署的前端工做
CSP 部署後端工做就是上面這段,無比簡單,但真正的工做量倒是在前端!
咱們部署 CSP 最大目的就是禁止非法腳本運行,只容許從指定域加載腳本運行,其它域和內聯腳本都應該禁止。咱們的工做就是要去掉全部內聯腳本。以前,Teambition 有兩處用到了內聯腳本。
一是全局變量 Teambition :
script
(function () {
window.teambition = {}
teambition.apiHost = '#{config.API_HOST}'
teambition.pushHost = '#{config.PUSH_HOST}'
teambition.uploadUrl = '#{config.FILE_HOST}'
teambition.loadingStart = Date.now()
})()
這是爲了方便從服務器獲取初始化配置信息,以及其它的前端構架內部的各類方便~。爲了部署 CSP 只好忍痛去除全局變量:)。從服務器獲取初始配置信息變成了這樣:
script(id="teambition-global", data-apihost="#{config.API_HOST}", data-pushhost="#{config.PUSH_HOST}", data-uploadurl="#{config.FILE_HOST}", data-spiderhost="#{config.SPIDER_HOST}", data-responsetime="#{timestamp}")
固然,從三萬行代碼中去除全局變量不是這麼簡單,細節這裏就不敘述了,加上修 BUG,花了我一成天,改完以後確實是舒服多了。
二是統計腳本:
前端朋友應該都知道如何嵌入百度、google 等統計服務,沒錯,就是在網頁中插入內聯腳本。
Teambition 作了一個叫 GTA 的開源封裝,將百度、google 和 mixpanel 三家統計分析服務融合到一塊兒。去內聯就是重構 GTA 模塊,這裏有一個要點,就是儘可能提早(調用前)用 appKey 將它們初始化。具體重構就不細說了,請直接看代碼。
最後,附送一個 CSP 規則生成器 http://cspisawesome.com/,Teambition 的 CSP 規則是在這裏生成的。