Web客戶端安全性最佳實踐

jobbole發表於2014-01-10

  得益於HTML5,Web應用中越來越多的邏輯從伺服器端遷移到了客戶端。因而,前端開發人員也需要更多關注安全性方面的問題。在這篇文章中,我會告訴你如何使你的應用更加安全。我會著重描述一些你可能從未聽說過的技術,而不是僅僅告訴你“別忘了對使用者提交的頁面資料做轉義(escape)”。

 HTTP?想都別想

  當然,我並不想讓你通過FTP或者普通的TCP協議來傳輸你的資料。我的意思是,如果你想讓你的使用者安全地訪問你的網站,你應該使用SSL(HTTPS)來加密你的資料傳輸。不僅要加密登陸節點或者關鍵資訊,而是要加密所有的資料。否則當使用者通過公用網路訪問你的應用時,他看見的內容說不定已經被別人“黑”掉了。這就叫中間人攻擊,見下圖:

main-in-the-middle

(譯者注:此處引用的原圖中筆誤,中間人攻擊的英文為Man-In-The-Middle Attack)

  如果你使用SSL,所有的資料在傳送之前就會被加密,即使攻擊者在網路中截獲了資料包,他也沒有辦法檢視或者篡改其中的內容。對於提升應用的安全性,這是目前為止最重要的一步。

 嚴格傳輸安全性標記(Strict-Transport-Security)

  如果你只想通過SSL來傳輸你的資料,那麼這個HTTP頭屬性會讓你覺得非常好用。如果伺服器端在響應頭中使用了這個標記(你也可以在頁面中使用<meta>標籤,不過這樣的話就會存在一個未被加密的請求),那麼所有從客戶端到伺服器端的資料都會被加密。使用方式如下:

Strict-Transport-Security: max-age=3600; includeSubDomains

  其中的includeSubDomains屬性是可選的,你可以使用它來加密當前域的子域,所有對子域的訪問也會被HTTPS加密。而其中的max-age屬性可以設定在多長的時間範圍內(以秒為單位)需要用SSL對頁面資料傳輸進行加密。不過可惜的是,目前只有Firefox、Chrome和Opera瀏覽器支援這個標記。

 Secure和HttpOnly屬性

  還有一種方法可以有效增強HTTP和HTTPS訪問的安全性,那就是使用SecureHttpOnly這兩個cookie屬性。前者能確保cookie的內容只通過SSL連線進行傳輸;而後者正好相反。如果你覺得這兩者互相矛盾,沒啥用處,那就錯了。它們告訴瀏覽器cookie的內容只能分別通過HTTP(S)協議進行訪問,從而避免了被別人輕易竊取,比如JavaScript中的document.cookie.

 通過Content-Security-Policy(CSP)標記來減少跨站指令碼攻擊(XSS)的危害

  如果你覺得依靠XSS過濾器能夠防範所有可能的XSS攻擊,不妨先看一看這篇文章,再好好思考一下。當然,為整個Web應用都配置上完備的防範措施也會存在一些問題,比如,可能拖累整個網站的效能。不過我還有一招。

  這招叫做Content-Security-Policy標記。它能讓你指定網站上所有指令碼和圖片等資源的源站點。此外,它還能阻止所有內聯(inline)的指令碼和樣式。即使有人在頁面評論或者回帖中嵌入了指令碼標籤,這些指令碼程式碼也不會被執行。CSP標記一般寫在HTTP頭中(也可以寫在HTML的<meta>標籤中),寫法如下:

Content-Security-Policy: policy

  其中的policy欄位代表一系列CSP屬性,下面列舉一些常用的屬性:

  • script-src – 設定可以接受的JavaScript程式碼的源站點
  • style-src – 設定可以接受的CSS樣式程式碼的源站點
  • connect-src – 定義瀏覽器可以通過XHR、WebSocket或者EventSource訪問哪些站點
  • font-src – 設定可以接受的字型檔案的源站點
  • frame-src – 定義瀏覽器可以通過iframe訪問哪些站點
  • img-src – 設定可以接受的圖片的源站點
  • media-src – 設定可以接受的音訊和視訊檔案的源站點
  • object-src – 設定可以接受的Flash和其它外掛的源站點

  如果沒有設定上述屬性,那麼瀏覽器預設會接受來自任何源站點的指令碼和資料。不過瀏覽器的預設屬性也能通過default-src屬性來設定。其它的屬性如果沒有設定的話,就會預設採用這個屬性中設定的值。此外,還有一個叫做sandbox的屬性,它可以讓瀏覽器以iframe的形式載入頁面。下面是一個CSP頭的例子:

Content-Security-Policy: default-src: 'self'; script-src: https://apis.google.com;

  在這個例子中,瀏覽器只會載入源自這個Web應用所在站點的資源(預設源設定為self),以及通過Google API伺服器獲取的指令碼。CSP有很多種靈活的用法,如果使用得當,可以有效提升Web應用的安全性。

  CSP的缺點

  當你使用CSP的時候,有一點千萬要記住:預設情況下,所有的內聯JavaScript指令碼都不會被執行。例如:

  內聯的事件監聽器:比如

<body onload="main();">

所有的javascript URL:比如

<a href="javascript:doTheClick()">

  之所以這樣,是因為瀏覽器無法區分你的內聯指令碼和黑客注入的指令碼。你需要通過JavaScript的addEventListener或者一些框架中類似的函式來重寫上述指令碼。某種程度上來看,這也不算一件壞事,它逼你不得不分離邏輯層的程式碼和展現層的程式碼,而你本來就應該這麼做。此外,CSP預設還會阻止所有eval()風格的程式碼的執行,包括setInterval/setTimeout中的字串和類似於new Function(‘return false’)之類的程式碼。

  CSP的可用性

  大部分時下流行的瀏覽器都支援CSP。Firefox、Chrome和Opera(包括手持裝置上的)使用標準的CSP頭。Safari(包括iOS中的)和安卓上的Chrome使用X-WebKit-CSP頭。IE10(僅支援sandbox屬性)使用X-Content-Security-Policy頭。所以,由於IE的支援(部分支援也是支援),你不僅可以著手使用CSP(除非你用的是Google Chrome Frame之類的東西),而且還能在各種實際的瀏覽器中執行,有效地改善Web應用的安全性。

 使用跨域資源共享(Cross Origin Resource Sharing)來代替JSONP

  目前由於瀏覽器同源策略的限制,JSONP常被用於從其它伺服器上獲取資料。通常的辦法是在指令碼中寫一個回撥函式,然後把回撥函式的名字寫在請求的URL中,像下面這樣:

function parseData(data) {
   ...
}
<script src="http://someserver.com/data?format=jsonp&callback=parseData"></script>

  但是這樣做會有很大的安全隱患。如果你請求資料的伺服器被黑了,那麼黑客就能在返回的資料中植入惡意程式碼,進而竊取使用者的隱私資訊。因為在瀏覽器看來,通過這種方法獲取的指令碼程式碼和正常的頁面程式碼沒什麼區別。

  正確的做法是使用跨域資源共享。它允許資源提供方在響應頭中加入一個特殊的標記,使你能通過XHR來獲取、解析並驗證資料。這樣就能避免惡意程式碼在你的應用中執行。

  這個方法需要在響應頭中加入的標記如下:

Access-Control-Allow-Origin: allowed origins

  這裡可以列舉一些可以接受的資料來源,以逗號隔開,使用萬用字元*來接受所有的資料來源。

  CORS可用性

  目前所有主流的瀏覽器都支援,除了Opera Mini。

  當然,更重要的是資料提供方能支援跨域資源共享,不過這就不是開發者能說了算的了。

 在iframe中使用sandbox屬性

  如果你使用iframe載入外部網站的內容,也別忘了它的安全問題。你可以通過iframe的sandbox屬性來增強iframe使用的安全性。通過設定sandbox屬性,可以使得iframe無法隨意跳轉頁面,無法執行外部指令碼,無法鎖定滑鼠,無法彈出新視窗,無法提交表單,等等。此外頁面上若干個iframe中載入的所有內容還必須來自唯一的源,也就不能使用localStorage等有悖於同源策略的東西。當然,如果有需要的話,你也可以通過顯式的設定來放寬限制,可以設定的屬性如下:

  • allow-same-origin –iframe只要各自符合同源規範即可
  • allow-scripts –iframe中可以執行JavaScript指令碼
  • allow-forms –iframe中可以提交表單
  • allow-pointer-lock –iframe中可以鎖定滑鼠
  • allow-popups – iframe中可以彈出新視窗
  • allow-top-navigation – iframe中可以完成頁面跳轉

  可用性

  目前iframe的sandbox屬性受各種主流瀏覽器支援,除了Opera Mini以外。

 結束語

  主要內容就是這些了。希望讀者能通過這篇文章學到一些新技術,能用於今後的專案中,更好的提升Web應用的安全性。得益於HTML5的發展,我們可以在Web上實現越來越豐富的功能。但是我們也不能掉以輕心,因為網路中攻擊和威脅無處不在,在敲第一行程式碼之前就要好好想一想安全性方面的問題。

  原文連結: nettuts+   翻譯: 伯樂線上 - njuyz

相關文章