得益於HTML5,Web應用中愈來愈多的邏輯從服務器端遷移到了客戶端。於是,前端開發人員也須要更多關注安全性方面的問題。在這篇文章中,我會告訴你如何使你的應用更加安全。我會着重描述一些你可能從未據說過的技術,而不是僅僅告訴你「別忘了對用戶提交的頁面數據作轉義(escape)」。javascript
固然,我並不想讓你經過FTP或者普通的TCP協議來傳輸你的數據。個人意思是,若是你想讓你的用戶安全地訪問你的網站,你應該使用SSL(HTTPS)來加密你的數據傳輸。不只要加密登錄節點或者關鍵信息,而是要加密全部的數據。不然當用戶經過公用網絡訪問你的應用時,他看見的內容說不定已經被別人「黑」掉了。這就叫中間人攻擊,見下圖:php
(譯者注:此處引用的原圖中筆誤,中間人攻擊的英文爲Man-In-The-Middle Attack)html
若是你使用SSL,全部的數據在發送以前就會被加密,即便攻擊者在網絡中截獲了數據包,他也沒有辦法查看或者篡改其中的內容。對於提高應用的安全性,這是目前爲止最重要的一步。前端
若是你只想經過SSL來傳輸你的數據,那麼這個HTTP頭屬性會讓你以爲很是好用。若是服務器端在響應頭中使用了這個標記(你也能夠在頁面中使用<meta>標籤,不過這樣的話就會存在一個未被加密的請求),那麼全部從客戶端到服務器端的數據都會被加密。使用方式以下:java
1
|
Strict-Transport-Security: max-age=
3600
; includeSubDomains
|
其中的includeSubDomains屬性是可選的,你可使用它來加密當前域的子域,全部對子域的訪問也會被HTTPS加密。而其中的max-age屬性能夠設置在多長的時間範圍內(以秒爲單位)須要用SSL對頁面數據傳輸進行加密。不過惋惜的是,目前只有Firefox、Chrome和Opera瀏覽器支持這個標記。json
還有一種方法能夠有效加強HTTP和HTTPS訪問的安全性,那就是使用Secure和HttpOnly這兩個cookie屬性。前者能確保cookie的內容只經過SSL鏈接進行傳輸;然後者正好相反。若是你以爲這二者互相矛盾,沒啥用處,那就錯了。它們告訴瀏覽器cookie的內容只能分別經過HTTP(S)協議進行訪問,從而避免了被別人輕易竊取,好比JavaScript中的document.cookie.api
若是你以爲依靠XSS過濾器可以防範全部可能的XSS攻擊,不妨先看一看這篇文章,再好好思考一下。固然,爲整個Web應用都配置上完備的防範措施也會存在一些問題,好比,可能拖累整個網站的性能。不過我還有一招。跨域
這招叫作Content-Security-Policy標記。它能讓你指定網站上全部腳本和圖片等資源的源站點。此外,它還能阻止全部內聯(inline)的腳本和樣式。即便有人在頁面評論或者回帖中嵌入了腳本標籤,這些腳本代碼也不會被執行。CSP標記通常寫在HTTP頭中(也能夠寫在HTML的<meta>標籤中),寫法以下:瀏覽器
1
|
Content-Security-Policy: policy
|
其中的policy字段表明一系列CSP屬性,下面列舉一些經常使用的屬性:安全
若是沒有設置上述屬性,那麼瀏覽器默認會接受來自任何源站點的腳本和數據。不過瀏覽器的默認屬性也能經過default-src屬性來設置。其它的屬性若是沒有設置的話,就會默認採用這個屬性中設置的值。此外,還有一個叫作sandbox的屬性,它可讓瀏覽器以iframe的形式加載頁面。下面是一個CSP頭的例子:
1
|
Content-Security-Policy:
default
-src:
'self'
; script-src: https:
//apis.google.com;
|
在這個例子中,瀏覽器只會加載源自這個Web應用所在站點的資源(默認源設置爲self),以及經過Google API服務器獲取的腳本。CSP有不少種靈活的用法,若是使用得當,能夠有效提高Web應用的安全性。
當你使用CSP的時候,有一點千萬要記住:默認狀況下,全部的內聯JavaScript腳本都不會被執行。例如:
內聯的事件監聽器:好比
1
|
<
body
onload
=
"main();"
>
|
全部的javascript URL:好比
1
|
<
a
href
=
"javascript:doTheClick()"
>
|
之因此這樣,是由於瀏覽器沒法區分你的內聯腳本和黑客注入的腳本。你須要經過JavaScript的addEventListener
或者一些框架中相似的函數來重寫上述腳本。某種程度上來看,這也不算一件壞事,它逼你不得不分離邏輯層的代碼和展示層的代碼,而你原本就應該這麼作。此外,CSP默認還會阻止全部eval()風格的代碼的執行,包括setInterval/setTimeout
中的字符串和相似於new Function(‘return false’)
之類的代碼。
大部分時下流行的瀏覽器都支持CSP。Firefox、Chrome和Opera(包括手持設備上的)使用標準的CSP頭。Safari(包括iOS中的)和安卓上的Chrome使用X-WebKit-CSP頭。IE10(僅支持sandbox屬性)使用X-Content-Security-Policy頭。因此,因爲IE的支持(部分支持也是支持),你不只能夠着手使用CSP(除非你用的是Google Chrome Frame之類的東西),並且還能在各類實際的瀏覽器中運行,有效地改善Web應用的安全性。
目前因爲瀏覽器同源策略的限制,JSONP常被用於從其它服務器上獲取數據。一般的辦法是在腳本中寫一個回調函數,而後把回調函數的名字寫在請求的URL中,像下面這樣:
1
2
3
|
function
parseData(data) {
...
}
|
1
|
<
script
src
=
"http://someserver.com/data?format=jsonp&callback=parseData"
></
script
>
|
可是這樣作會有很大的安全隱患。若是你請求數據的服務器被黑了,那麼黑客就能在返回的數據中植入惡意代碼,進而竊取用戶的隱私信息。由於在瀏覽器看來,經過這種方法獲取的腳本代碼和正常的頁面代碼沒什麼區別。
正確的作法是使用跨域資源共享。它容許資源提供方在響應頭中加入一個特殊的標記,使你能經過XHR來獲取、解析並驗證數據。這樣就能避免惡意代碼在你的應用中執行。
這個方法須要在響應頭中加入的標記以下:
1
|
Access-Control-Allow-Origin: allowed origins
|
這裏能夠列舉一些能夠接受的數據源,以逗號隔開,使用通配符*來接受全部的數據源。
目前全部主流的瀏覽器都支持,除了Opera Mini。
固然,更重要的是數據提供方能支持跨域資源共享,不過這就不是開發者能說了算的了。
若是你使用iframe加載外部網站的內容,也別忘了它的安全問題。你能夠經過iframe的sandbox屬性來加強iframe使用的安全性。經過設置sandbox屬性,可使得iframe沒法隨意跳轉頁面,沒法執行外部腳本,沒法鎖定鼠標,沒法彈出新窗口,沒法提交表單,等等。此外頁面上若干個iframe中加載的全部內容還必須來自惟一的源,也就不能使用localStorage等有悖於同源策略的東西。固然,若是有須要的話,你也能夠經過顯式的設置來放寬限制,能夠設置的屬性以下:
目前iframe的sandbox屬性受各類主流瀏覽器支持,除了Opera Mini之外。
主要內容就是這些了。但願讀者能經過這篇文章學到一些新技術,能用於從此的項目中,更好的提高Web應用的安全性。得益於HTML5的發展,咱們能夠在Web上實現愈來愈豐富的功能。可是咱們也不能掉以輕心,由於網絡中攻擊和威脅無處不在,在敲第一行代碼以前就要好好想想安全性方面的問題。