? ? ? 前言:HTML5出現后,網絡安全更加受到廣泛的關注。Web對于網絡安全有哪些改進?我們如何來面對越來越危險的網絡欺詐和攻擊?下面的文章談到了W3C對于這個問題的最新解決方案。未來有機會的話,我會針對XSS、P3P、同源策略、CORS(跨域資源共享)和CSP進行關于HTML5內容安全的現場分享。
? ? ??------------------------華麗的分界線
? ? ??注意:本文所討論的API還未最終確定,請在自己的項目中謹慎使用。
? ? ??萬維網的安全策略植根于[同源策略](http://en.wikipedia.org/wiki/Same_origin_policy)。例如[http://blog.csdn.net/hfahe](http://blog.csdn.net/hfahe)的代碼只能訪問[http://blog.csdn.net](http://blog.csdn.net/)的數據,而沒有訪問[http://www.baidu.com](http://www.baidu.com/)的權限。每個來源都與網絡的其它部分分隔開,為開發人員構建了一個安全的沙箱。理論上這是完美的,但是現在攻擊者已經找到了聰明的方式來破壞這個系統。
? ? ??這就是[XSS跨站腳本攻擊](http://en.wikipedia.org/wiki/Cross-site_scripting),通過虛假內容和誘騙點擊來繞過同源策略。這是一個很大的問題,如果攻擊者成功注入代碼,有相當多的用戶數據會被泄漏。
? ? ??現在我們介紹一個全新的、有效的安全防御策略來減輕這種風險,這就是**內容安全策略**(ContentSecurity Policy,CSP)。
**來源白名單**
? ? ??XSS攻擊的核心是利用了瀏覽器無法區分腳本是被第三方注入的,還是真的是你應用程序的一部分。例如Google +1按鈕會從[https://apis.google.com/js/plusone.js](https://apis.google.com/js/plusone.js)加載并執行代碼,但是我們不能指望從瀏覽器上的圖片就能判斷出代碼是真的來自apis.google.com,還是來自apis.evil.example.com。瀏覽器下載并執行任意代碼的頁面請求,而不論其來源。

? ? ??CSP定義了Content-Security-PolicyHTTP頭來允許你創建一個可信來源的白名單,使得瀏覽器只執行和渲染來自這些來源的資源,而不是盲目信任服務器提供的所有內容。即使攻擊者可以找到漏洞來注入腳本,但是因為來源不包含在白名單里,因此將不會被執行。
? ? ??以上面Google +1按鈕為例,因為我們相信apis.google.com提供有效的代碼,以及我們自己,所以可以定義一個策略,允許瀏覽器只會執行下面兩個來源之一的腳本。
? ? ??Content-Security-Policy:script-src 'self' [https://apis.google.com](https://apis.google.com/)
? ? ??是不是很簡單?script-src可以為指定頁面控制腳本相關權限。這樣瀏覽器只會下載和執行來自[http://apis.google.com](http://apis.google.com/)和本頁自身的腳本。
? ? ??一旦我們定義了這個策略,瀏覽器會在檢測到注入代碼時拋出一個錯誤(請注意是什么瀏覽器)。
**內容安全策略適用于所有常用資源**
? ? ??雖然腳本資源是最明顯的安全隱患,但是CSP還提供了一套豐富的指令集,允許頁面控制加載各種類型的資源,例如如下的類型:
- content-src:限制連接的類型(例如XHR、WebSockets和EventSource)
- font-src:控制網絡字體的來源。例如可以通過font-src [https://themes.googleusercontent.com](https://themes.googleusercontent.com/)來使用Google的網絡字體。
- frame-src:列出了可以嵌入的frame的來源。例如frame-src?https://youtube.com只允許嵌入YouTube的視頻。。
- img-src:定義了可加載圖像的來源。
- media-src:限制視頻和音頻的來源。
- object-src:限制Flash和其他插件的來源。
- style-src:類似于Script-src,只是作用于css文件。
? ? ??默認情況下,所有的設置都是打開的,不做任何限制。你可以以分號分隔多個指令,但是類似于script-src [https://host1.com](https://host1.com/);script-src[https://host2.com](https://host2.com/)的形式,第二個指令將會被忽略。正確的寫法是script-src [https://host1.com](https://host1.com/)[https://host2.com](https://host2.com/)。
? ? ??例如,你有一個應用需要從內容分發網絡(CDN,例如https://cdn.example.net)加載所有的資源,并且知道不需要任何frame和插件的內容,你的策略可能會像下面這樣:
~~~
Content-Security-Policy:default-src https://cdn.example.net; frame-src 'none'; object-src 'none'
~~~
**細節**
? ? ??我在例子里使用的HTTP頭是Content-Security-Policy,但是現代瀏覽器已經通過前綴來提供了支持:Firefox使用x-Content-Security-Policy,WebKit使用X-WebKit-CSP。未來會逐步過渡到統一的標準。
? ? ??策略可以根據每個不同的頁面而設定,這提供了很大的靈活度。因為你的站點可能有的頁面有Google +1的按鈕,而有的則沒有。
? ? ??每個指令的來源列表可以相當靈活,你可以指定模式(data:, https:),或者指定主機名在一個范圍(example.com,它匹配主機上的任意來源、任意模式和任意端口),或者指定一個完整的URI([https://example.com:443](https://example.com/),特指https協議,example.com域名,443端口)。
? ? ??你在來源列表中還可以使用四個關鍵字:
- “none”:你可能期望不匹配任何內容
- “self”:與當前來源相同,但不包含子域
- “unsafe-inline”:允許內聯Javascript和CSS
- “unsafe-eval”:允許文本到JS的機制例如eval
? ? ??請注意,這些關鍵詞需要加引號。
**沙箱**
? ? ??這里還有另外一個值得討論的指令:sandbox。和其他指令有些不一致,它主要是控制頁面上采取的行為,而不是頁面能夠加載的資源。如果設置了這個屬性,頁面就表現為一個設置了sandbox屬性的frame一樣。這對頁面有很大范圍的影響,例如防止表單提交等。這有點超出了本文的范圍,但是你可以在[HTML5規范的“沙箱標志設置”章節](http://www.whatwg.org/specs/web-apps/current-work/multipage/origin-0.html#sandboxing-flag-set)找到更多信息。
**有害的內聯代碼**
? ? ??CSP基于來源白名單,但是它不能解決XSS攻擊的最大來源:內聯腳本注入。如果攻擊者可以注入包含有害代碼的script標簽(<script>sendMyDataToEvilDotCom();</script>),瀏覽器并沒有好的機制來區分這個標簽。CSP只能通過完全禁止內聯腳本來解決這個問題。
? ? ??這個禁止項不僅包括腳本中嵌入的script標簽,還包括內聯事件處理程序和javascrpt:這種URL。你需要把script標簽的內容放到一個外部文件里,并且用適當的addEventListener的方式替換javascript:和<a… onclick=”[JAVASCRIPT]”>。例如,你可能會把下面的表單:
~~~
<script>
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
</script>
<button onclick='doAmazingThings();'>Am I amazing?</button>
~~~
? ? ??重寫為下面的形式:
~~~
<!-- amazing.html -->
<script src='amazing.js'></script>
<button id='amazing'>Am I amazing?</button>
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentReady', function () {
document.getElementById('amazing')
.addEventListener('click', doAmazingThings);
});
~~~
? ? ??無論是否使用CSP,以上的代碼其實有更大的優點。內聯JavaScript完全混合了結構和行為,你不應該這么做。另外外聯資源更容易進行瀏覽器緩存,開發者更容易理解,并且便于編譯和壓縮。如果采用外聯代碼,你會寫出更好的代碼。
? ? ??內聯樣式需要以同樣的方式進行處理,無論是style屬性還是style標簽都需要提取到外部樣式表中。這樣可以防止各式各樣[神奇的數據泄漏方式](http://scarybeastsecurity.blogspot.com/2009/12/generic-cross-browser-cross-domain.html)。
? ? ??如果你必須要有內聯腳本和樣式,可以為script-src?or?style-src屬性設定'unsafe-inline值。但是不要這樣做,禁止內聯腳本是CSP提供的最大安全保證,同時禁止內聯樣式可以讓你的應用變得更加安全和健壯。這是一個權衡,但是非常值得。
**Eval**
? ? ??即便攻擊者不能直接注入腳本,他可能會誘使你的應用把插入的文本轉換為可執行腳本并且自我執行。eval()?,?newFunction()?,?setTimeout([string], ...)?和setInterval([string], ...)?都可能成為這種危險的載體。CSP針對這種風險的策略是,完全阻止這些載體。
? ? ??這對你構建應用的方式有一些影響:
? ? ??通過內置的JSON.parse解析JSON,而不依靠eval。IE8以后的瀏覽器都支持本地JSON操作,這是完全安全的。
? ? ??通過內聯函數代替字符串來重寫你setTimeout和setInterval的調用方式。例如:? ??
~~~
setTimeout("document.querySelector('a').style.display = 'none';", 10);
~~~
? ? ??可以重寫為:
~~~
setTimeout(function () { document.querySelector('a').style.display = 'none'; }, 10);
~~~
避免運行時的內聯模版:許多模版庫都使用new Function()以加速模版的生成。這對動態程序來說非常棒,但是對惡意文本來說存在風險。
**報告**
? ? ??CSP可以在服務器端阻止不可信的資源對用戶來說非常有用,但是對于獲取各種發送到服務器的通知來說對我們卻非常有用,這樣我們就能識別和修復任何惡意腳本注入。為此你可以通過report-uri指令指示瀏覽器發送JSON格式的攔截報告到某個地址。
~~~
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
~~~
? ? ??報告看起來會像下面這樣:
~~~
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/",
"blocked-uri": "http://evil.example.com/evil.js",
"violated-directive": "script-src 'self' https://apis.google.com",
"original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
}
}
~~~
? ? ??其中包含的信息會幫助你識別攔截的情況,包括攔截發生的頁面(document-uri),頁面的referrer,違反頁面策略的資源(blocked-uri),所違反的指令(violated-directive)以及頁面所有的內容安全策略(original-policy)。
**現實用法**
? ? ??CSP現在在Chrome 16+和Firefox 4+的瀏覽器上可用,并且它在IE10上預計會獲得有限的支持。Safari目前還不支持,但是WebKit每晚構建版已經可用,所以預計Safari將會在下面的迭代中提供支持。
下面讓我們看一些常用的用例:
**實際案例1:社會化媒體widget**
- Google [+1 button](http://www.google.com/intl/en/webmasters/+1/button/index.html)包括來自[https://apis.google.com](https://apis.google.com/)的腳本,以及嵌入自https://plusone.google.com的iframe。你的策略需要包含這些源來使用Google +1的按鈕。最簡單的策略是script-src [https://apis.google.com](https://apis.google.com/); frame-src https://plusone.google.com。你還需要確保Google提供的JS片段存放在外部的JS文件里。
- Facebook的[Like按鈕](http://developers.facebook.com/docs/reference/plugins/like/)有許多種實現方案。我建議你堅持使用iframe版本,因為它可以和你站點的其它部分保持很好的隔離。這需要使用frame-src [https://facebook.com](https://facebook.com/)指令。請注意,默認情況下,Facebook提供的iframe代碼使用的是相對路徑//facebook.com,請把這段代碼修改為[https://facebook.com](https://facebook.com/),HTTP你沒有必要可以不使用。
- Twitter的[Tweet按鈕](https://twitter.com/about/resources/buttons)依賴于script和frame,都來自于[https://platform.twitter.com(Twitter](https://platform.twitter.com%28twitter/)默認提供的是相對URL,請在復制的時候編輯代碼來指定為HTTPS方式)。
? ? ??其它的平臺有相似的情況,可以類似的解決。我建議把default-src設置為none,然后查看控制臺來檢查你需要使用哪些資源來確保widget正常工作。
? ? ??使用多個widget非常簡單:只需要合并所有的策略指令,記住把同一指令的設置都放在一起。如果你想使用上面這三個widget,策略看起來會像下面這樣:
~~~
script-src https://apis.google.com https://platform.twitter.com; frame-src https://plusone.google.com https://facebook.com https://platform.twitter.com
~~~
? ? ??**實際案例2:防御**
? ? ??假設你訪問一個銀行網站,并且希望確保只加載你所需的資源。在這種情況下,開始設置一個默認的權限來阻止所有的內容(default-src ‘none’),并且從這從頭構建策略。
? ? ??比如,銀行網站需要從來自[https://cdn.mybank.net](https://cdn.mybank.net/)的CDN加載圖像、樣式和腳本,并且通過XHR連接到[https://api.mybank.com/](https://api.mybank.com/)來拉取各種數據,還需要使用frame,但是frame都來自非第三方的本地頁面。網站上沒有Flash、字體和其他內容。這種情況下我們可以發送最嚴格的CSP頭是:? ?
~~~
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; frame-src 'self'
~~~
**實際案例3:只用SSL**
? ? ??一個婚戒論壇管理員希望所有的資源都通過安全的方式進行加載,但是不想真的編寫太多代碼;重寫大量第三方論壇內聯腳本和樣式的代碼超出了他的能力。所以以下的策略將會是非常有用的:
~~~
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
~~~
? ? ??盡管default-src指定了https,腳本和樣式不會自動繼承。每個指令將會完全覆蓋默認資源類型。
**未來**
? ? ??W3C的[Web應用安全工作組](http://www.w3.org/2011/webappsec/)正在制定內容安全策略規范的細節,1.0版本將要進入最后修訂階段,它和本文描述的內容已經非常接近。而public-webappsec@郵件組正在討論1.1版本,瀏覽器廠商也在努力鞏固和改進CSP的實現。
? ? ??CSP 1.1在畫板上有一些有趣的地方,值得單獨列出來:
? ? ??**通過meta標簽添加策略**:CSP的首選設置方式是HTTP頭,它非常有用,但是通過標記或者腳本設置會更加直接,不過目前還未最終確定。WebKit已經實現了[通過meta元素進行權限設置](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#html-meta-element--experimenta)的特性,所以你現在可以在Chrome下嘗試如下的設置:在文檔頭添加<metahttp-equiv="X-WebKit-CSP" content="[POLICY GOES HERE]">。
? ? ??你甚至可以在運行時通過腳本來添加策略。
? ? ??**DOM API:**如果CSP的下一個迭代添加了這個特性,你可以通過Javascript來查詢頁面當前的安全策略,并根據不同的情況進行調整。例如在eval()是否可用的情況下,你的代碼實現可能會有些許不同。這對JS框架的作者來說非常有用;并且API規范目前還非常不確定,你可以在[規范草案的腳本接口章節](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-interfaces)找到最新的迭代版本。**
? ? ??**新的指令**:許多新指令正在討論中,包括[script-nonce](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-nonce--experimental):只有明確指定的腳本元素才能使用內聯腳本;[plugin-types](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#plugin-types--experimental):這將限制插件的類型;[form-action](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#form-action--experimental):允許form只能提交到特定的來源。
? ? ??如果你對這些未來特性的討論感興趣,可以閱讀[郵件列表的歸檔](http://lists.w3.org/Archives/Public/public-webappsec/)或者加入郵件列表。
? ? ??本文譯自:[http://www.html5rocks.com/en/tutorials/security/content-security-policy/](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
? ? ??轉載請注明:[來自蔣宇捷的博客](http://blog.csdn.net/hfahe)
- 前言
- AutoPager的簡單實現
- 利用CSS3特性巧妙實現漂亮的DIV箭頭
- IE9在Win7下任務欄新特性簡介
- 瀏覽器九宮格的簡單實現
- Raphael js庫簡介
- 使用CSS3構建Ajax加載動畫
- 用CSS3創建動畫價格表
- 用CSS3實現瀏覽器的縮放功能
- 用純CSS3實現QQ LOGO
- 用CSS3創建旋轉載入器
- 使用Javascript開發移動應用程序
- 用HTML5創建超酷圖像灰度漸變效果
- 使用CSS3創建文字顏色漸變(CSS3 Text Gradient)
- 僅用CSS創建立體旋轉幻燈片
- 如何創建跨瀏覽器的HTML5表單
- 用CSS3實現動畫進度條
- HTML5 Guitar Tab Player
- 奇妙的HTML5 Canvas動畫實例
- 談HTML5和CSS3的國際化支持
- 實現跨瀏覽器的HTML5占位符
- 前端開發必備工具:WhatFont Bookmarklet-方便的查詢網頁上的字體
- 使用HTML5和CSS3來創建幻燈片
- HTML5之美
- 如何使用HTML5創建在線精美簡歷
- 以小見大、由淺入深-談如何面試Javascript工程師
- 快速入門:HTML5強大的Details元素
- 用CSS3實現圖像風格
- HTML5視頻字幕與WebVTT
- 用純CSS3實現Path華麗動畫
- 用3個步驟實現響應式網頁設計
- 遇見CSS3濾鏡
- 關于CSS3濾鏡的碎念
- 用純CSS3繪制萌系漫畫人物動態頭像
- CSS3新的鼠標樣式介紹
- 用HTML5獻上愛的3D玫瑰
- 對HTML5 Device API相關規范的解惑
- 如何使用HTML5實現拍照上傳應用
- 2012第一季度國外HTML5移動開發趨勢
- HTML5新特性:范圍樣式
- 百度開發者大會-《用HTML5新特性開發移動App》PPT分享
- Chrome 19對于HTML5最新支持的動態:電池狀態API,全屏API,震動API,語音API
- 遇見Javascript類型數組(Typed Array)
- 用HTML5 Audio API開發游戲音樂
- 用HTML5實現人臉識別
- 用Javascript實現人臉美容
- Chrome 20對于HTML5最新支持的動態:顏色輸入,網絡信息API,CSS著色器
- 用HTML5實現手機搖一搖的功能
- 用HTML5實現iPad應用無限平滑滾動
- 用非響應式設計構建跨端Web App
- 了解SVG
- HTML5圖像適配介紹
- HTML5安全:內容安全策略(CSP)簡介
- HTML5安全:CORS(跨域資源共享)簡介
- 用CSS3 Region和3D變換實現書籍翻頁效果
- 談談移動App的思維誤區
- Chrome新特性:文件夾拖拽支持
- 《關注HTML5安全》
- HTML5安全風險詳析之一:CORS攻擊
- HTML5安全風險詳析之二:Web Storage攻擊
- HTML5圖像適配最新進展:響應式圖片規范草案
- HTML5移動Web App相關標準狀態及路線圖
- HTML5安全風險詳析之三:WebSQL攻擊
- Chrome引入WebRTC支持視頻聊天App
- HTML5安全風險詳析之四:Web Worker攻擊
- HTML5安全風險詳析之五:劫持攻擊
- HTML5安全風險詳析之六:API攻擊
- HTML5安全攻防詳析之七:新標簽攻擊
- 在iOS Safari中播放離線音頻
- 使用WebRTC實現遠程屏幕共享
- Firefox、Android、iOS遇見WebRTC
- HTML5光線傳感器簡介
- HTML5安全攻防詳析之八:Web Socket攻擊
- HTML5安全攻防詳析之完結篇:HTML5對安全的改進
- 激動人心!在網頁上通過語音輸入文字 - HTML5 Web Speech API介紹
- Web滾動性能優化實戰
- 用CSS3設計響應式導航菜單
- 用HTML5構建高性能視差網站
- 漫談@supports與CSS3條件規則
- HTML5下載屬性簡介
- 如何開發優秀的HTML5游戲?-迪斯尼《尋找奧茲之路》游戲技術詳解(一)
- 如何開發優秀的HTML5游戲?-迪斯尼《尋找奧茲之路》游戲技術詳解(二)
- 趨勢:Chrome為打包應用提供強大新特性
- 從HTML5移動應用現狀談發展趨勢
- 基于HTML5的Web跨設備超聲波通信方案