深入了解XSS 和 CSRF

const decodingMap = {

'

'>': '>',

'"': '"',

'&': '&',

'

': ' '

}

4.3、輸出檢查

用戶的輸入會存在問題,服務端的輸出也會存在問題。一般來說,除富文本的輸出外,在變量輸出到 HTML 頁面時,可以使用編碼或轉義的方式來防禦 XSS 攻擊。例如利用 sanitize-html 對輸出內容進行有規則的過濾之後再輸出到頁面中。

二、CSRF

CSRF,即 Cross Site Request Forgery,中譯是跨站請求偽造,是一種劫持受信任用戶向服務器發送非預期請求的攻擊方式。

通常情況下,CSRF 攻擊是攻擊者藉助受害者的 Cookie 騙取服務器的信任,可以在受害者毫不知情的情況下以受害者名義偽造請求發送給受攻擊服務器,從而在並未授權的情況下執行在權限保護之下的操作。

在舉例子之前,先說說瀏覽器的 Cookie 策略。

1、瀏覽器的 Cookie 策略

Cookie 是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶併發送到服務器上。Cookie 主要用於以下三個方面:

  • 會話狀態管理(如用戶登錄狀態、購物車、遊戲分數或其它需要記錄的信息)
  • 個性化設置(如用戶自定義設置、主題等)
  • 個性化設置(如用戶自定義設置、主題等)

而瀏覽器所持有的 Cookie 分為兩種:

  • Session Cookie(會話期 Cookie):會話期 Cookie 是最簡單的Cookie,它不需要指定過期時間(Expires)或者有效期(Max-Age),它僅在會話期內有效,瀏覽器關閉之後它會被自動刪除。
  • Permanent Cookie(持久性 Cookie):與會話期 Cookie 不同的是,持久性 Cookie 可以指定一個特定的過期時間(Expires)或有效期(Max-Age)。

res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

上述代碼創建了兩個 Cookie:mycookie 和 test,前者屬於會話期 Cookie,後者則屬於持久性 Cookie。當我們去查看 Cookie 相關的屬性時,不同的瀏覽器對會話期 Cookie 的 Expires 屬性值會不一樣:

Firefox:

深入瞭解XSS 和 CSRF

Chrome:

深入瞭解XSS 和 CSRF

此外,每個 Cookie 都會有與之關聯的域,這個域的範圍一般通過 donmain 屬性指定。如果 Cookie 的域和頁面的域相同,那麼我們稱這個 Cookie 為第一方 Cookie(first-party cookie),如果 Cookie 的域和頁面的域不同,則稱之為第三方 Cookie(third-party cookie)。一個頁面包含圖片或存放在其他域上的資源(如圖片)時,第一方的 Cookie 也只會發送給設置它們的服務器。

2、通過 Cookie 進行 CSRF 攻擊

假設有一個 bbs 站點:http://www.c.com,當登錄後的用戶發起如下 GET 請求時,會刪除 ID 指定的帖子:

http://www.c.com:8002/content/delete/:id

如發起 //p2.ttnews.xyz/5b578c70eae5e1ff28cf21dc.jpg 請求時,會刪除 id 為 87343 的帖子。當用戶登錄之後,會設置如下 cookie:

res.setHeader('Set-Cookie', ['user=22333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

深入瞭解XSS 和 CSRF

user 對應的值是用戶 ID。然後構造一個頁面 A:

CSRF 攻擊者準備的網站:

CSRF 攻擊者準備的網站:

頁面 A 使用了一個 img 標籤,其地址指向了刪除用戶帖子的鏈接:

深入瞭解XSS 和 CSRF

可以看到,當登錄用戶訪問攻擊者的網站時,會向 www.c.com 發起一個刪除用戶帖子的請求。此時若用戶在切換到 www.c.com 的帖子頁面刷新,會發現ID 為 87343 的帖子已經被刪除。

由於 Cookie 中包含了用戶的認證信息,當用戶訪問攻擊者準備的攻擊環境時,攻擊者就可以對服務器發起 CSRF 攻擊。在這個攻擊過程中,攻擊者藉助受害者的 Cookie 騙取服務器的信任,但並不能拿到 Cookie,也看不到 Cookie 的內容。而對於服務器返回的結果,由於瀏覽器同源策略的限制,攻擊者也無法進行解析。因此,攻擊者無法從返回的結果中得到任何東西,他所能做的就是給服務器發送請求,以執行請求中所描述的命令,在服務器端直接改變數據的值,而非竊取服務器中的數據。

3、CSRF 攻擊的防範

對 CSRF 攻擊的防範措施主要有如下幾種方式。

3.1、驗證碼

驗證碼被認為是對抗 CSRF 攻擊最簡潔而有效的防禦方法。

從上述示例中可以看出,CSRF 攻擊往往是在用戶不知情的情況下構造了網絡請求。而驗證碼會強制用戶必須與應用進行交互,才能完成最終請求。因為通常情況下,驗證碼能夠很好地遏制 CSRF 攻擊。但驗證碼並不是萬能的,因為出於用戶考慮,不能給網站所有的操作都加上驗證碼。因此驗證碼只能作為防禦 CSRF 的一種輔助手段,而不能作為最主要的解決方案。

3.2、Referer Check

根據 HTTP 協議,在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。通過 Referer Check,可以檢查請求是否來自合法的”源”。如果用戶要刪除自己的帖子,那麼先要登錄 www.c.com,然後找到對應的頁面,發起刪除帖子的請求。此時,Referer 的值是 http://www.c.com;當請求是從 www.a.com 發起時,Referer 的值是 http://www.a.com 了。因此,要防禦 CSRF 攻擊,只需要對於每一個刪帖請求驗證其 Referer 值,如果是以 www.c.com 開頭的域名,則說明該請求是來自網站自己的請求,是合法的。如果 Referer 是其他網站的話,則有可能是 CSRF 攻擊,可以拒絕該請求。

針對上文的例子,可以在服務端增加如下代碼:

if (req.headers.referer !== 'http://www.c.com:8002/') {

res.write('csrf 攻擊');

return;

}

referer check:Referer Check 不僅能防範 CSRF 攻擊,另一個應用場景是 “防止圖片盜鏈”。

3.3、添加 token 驗證

CSRF 攻擊之所以能夠成功,是因為攻擊者可以完全偽造用戶的請求,該請求中所有的用戶驗證信息都是存在於 Cookie 中,因此攻擊者可以在不知道這些驗證信息的情況下直接利用用戶自己的 Cookie 來通過安全驗證。要抵禦 CSRF,關鍵在於在請求中放入攻擊者所不能偽造的信息,並且該信息不存在於 Cookie 之中。可以在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內容不正確,則認為可能是 CSRF 攻擊而拒絕該請求。

三、總結

本文主要介紹了 XSS 和 CSRF 的攻擊原理和防禦措施。在 Web 安全領域,除了這兩種常見的攻擊方式,也存在這 SQL 注入等其它攻擊方式,這不在本文的討論範圍之內,如果你對其感興趣,可以閱讀SQL注入技術專題的專欄詳細瞭解相關信息。


分享到:


相關文章: