web安全機制問題詳解之二:CSRF

什麼是CSRF

CSRF(Cross-site request forgery)跨站請求僞造:攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送請求。利用受害者在被攻擊網站已經獲取的註冊憑證,繞事後臺的用戶驗證,達到冒充用戶對被攻擊網站執行某項操做的目的。html

一個典型的CSRF攻擊流程:前端

  • 用戶登陸a.com,並保留了登陸憑證(cookie)
  • 攻擊者引誘用戶訪問b.com,如,誘導性文字按鈕等
  • b.com向a.com發送了一個請求:a.com/act=xx。瀏覽器會默認攜帶a.com的cookie
  • a.com接收到請求後,對請求進行驗證,並確認是受害用戶的憑證,誤覺得是用戶本身發送的請求
  • a.com以用戶名義執行了act=xx
  • 攻擊完成,攻擊者在用戶不知情的狀況下,冒充用戶,讓a.com執行了本身定義的操做

例如:算法

用戶A瀏覽Gmail郵件,因好奇點擊了一封「甩賣比特幣,只要998」的廣告郵件。打開後一片空白,隨後用戶A關閉了頁面。但此時CSRF攻擊已經完成,用戶A的Gmail郵件將逐一轉發到黑客的郵箱。具體是怎麼發生的呢,關鍵在於那個空白頁面的源碼:後端

<form method="POST" action="https://mail.google.com/mail/h/ewt1jmuj4ddv/?v=prf" enctype="multipart/form-data"> 
    <input type="hidden" name="cf2_emc" value="true"/> 
    <input type="hidden" name="cf2_email" value="hacker@hakermail.com"/> 
    .....
    <input type="hidden" name="irf" value="on"/> 
    <input type="hidden" name="nvp_bu_cftb" value="Create Filter"/> 
</form> 
<script> 
    document.forms[0].submit();
</script>複製代碼

這個頁面只要一打開就會向Gmail發送一個post請求。請求中,執行了‘Create Filter’命令(自動轉發郵件),將全部郵件轉發到黑客郵箱hacker@hakermail.com。因爲A剛登錄了Gmail,用戶登陸憑證被保存在cookie中,因此這個空白頁發出的post請求就攜帶了登錄證實,因而成功給用戶A配置了過濾器。黑客能夠查看全部用戶A的郵件,包括一些敏感信息:郵箱驗證碼等等。此事件原型是2007年Gmail的CSRF漏洞:www.davidairey.com/google-Gmai…。目前此漏洞已修復。api

幾種常見的CSRF攻擊

GET類型攻擊:http請求時,敏感參數跟在url後面,攻擊者很容易獲取併發送包含受害者信息的跨域請求。跨域

POST類型攻擊:如上案列所示。瀏覽器

連接類型攻擊:頁面中注入惡意連接,誘導用戶點擊跳轉。安全

防禦策略

據上所示,CSRF一般是由第三方網站發起,所以能夠經過加強自身網站的安全性來防護:bash

  • 同源策略
  • token驗證

同源檢測服務器

同源策略上分爲兩部分:一是http請求接口的同源,還有一個是cookie的domain屬性的同源。

1. http請求,可使用origin header、referer header肯定來源域名。

在部分請求中,請求的header中會攜帶origin字段,表明請求的域名;也有不存在origin的狀況,IE11對同源的定義有別於其餘瀏覽器,還有一個就是302重定向以後origin不包含在重定向的請求中,由於重定向請求是定向到新的服務器,避免泄露origin信息。

http請求header中還有另一個記錄該請求來源地址的屬性referer。referer值是由瀏覽器提供的,不可排除瀏覽器自身安全性問題,和部分狀況下攻擊者隱藏甚至篡改本身請求的referer。在同源策略下,能夠把referer屬性設置成same-origin,對於同源的額連接和引用會發送referer,對於跨域則不攜帶referer。

設置referer的三種方法:在csp設置;頁面頭部增設meta標籤;a標籤增長referer屬性

<a href="https://www.baidu.com/" ref="noreferrer">跳到百度</a>複製代碼

可是,在如下狀況下referer沒有或者不可信:

  • IE六、7使用window.location.href=url進行界面跳轉,會丟失referer
  • IE六、7使用window.open,也會丟失referer
  • https跳到http,全部瀏覽器都會丟失referer
  • 點擊flash到達另一個網站時,referer不可信

2. 在瀏覽器種下cookie時,若明確cookie的domain屬性(一級域名或是子域名),即僅在domain指定的域下的接口才會自動攜帶cookie,能夠解決部分跨域問題,但仍不能避免攻擊者僞造的域名和網站同域(本地服務器proxy代理請求時)。還能夠設置cookie爲Httponly,這樣cookie只能在請求中被攜帶,沒法用document.cooke讀取、修改。

token驗證

這裏的token驗證也有兩種,一種是CSRF token的加解密校驗,還有一個是雙重Cookie驗證。

1. CSRF token

用戶打開頁面時,服務器會個每一個用戶生成惟一的token,這個token是通過精密算法對數據進行加密,通常包括隨機字符串和時間戳。token會存在服務器的session中。頁面提交的請求都會攜帶這個token,當服務器拿到token後用相應解密算法獲得時間戳、及加密字符串,再和服務器session中存儲的token信息做比較來判斷該請求的有效性,這類token通常是隨機字符串。

分佈式校驗

在大型網站中,使用session存儲token會帶來很大壓力。訪問單臺服務器session是同一個。可是如今的大型網站中,咱們的服務器一般不止一臺,多是幾十臺甚至幾百臺之多,甚至多個機房均可能在不一樣的省份,用戶發起的HTTP請求一般要通過像Ngnix之類的負載均衡器以後,再路由到具體的服務器上,因爲Session默認存儲在單機服務器內存中,所以在分佈式環境下同一個用戶發送的屢次HTTP請求可能會前後落到不一樣的服務器上,致使後面發起的HTTP請求沒法拿到以前的HTTP請求存儲在服務器中的Session數據,從而使得Session機制在分佈式環境下失效,所以在分佈式集羣中CSRF Token須要存儲在Redis之類的公共存儲空間。

目前的解決辦法就是採用Encrypted Token Pattern方式,計算出一個結果,而不是隨機字符串。這樣就無需將token存儲在session中,只須要在拿到token的時候再計算一次就行。

Token是一個比較有效的CSRF防禦方法,只要頁面沒有XSS漏洞泄露Token,那麼接口的CSRF攻擊就沒法成功。其次,驗證碼和密碼其實也有CSRF token的做用。

2. 雙重Cookie驗證

雙重Cookie採用如下流程:

  • 在用戶訪問網站頁面時,向請求域名注入一個Cookie,內容爲隨機字符串(例如csrfcookie=v8g9e4ksfhw)。
  • 在前端向後端發起請求時,取出Cookie,並添加到URL的參數中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)。
  • 後端接口驗證Cookie中的字段與URL參數中的字段是否一致,不一致則拒絕。

此方法相對於CSRF Token就簡單了許多。能夠直接經過先後端攔截的的方法自動化實現。後端校驗也更加方便,只需進行請求中字段的對比,而不須要再進行查詢和存儲Token。

固然,此方法並無大規模應用,其在大型網站上的安全性仍是沒有CSRF Token高,緣由咱們舉例進行說明。

因爲任何跨域都會致使前端沒法獲取Cookie中的字段(包括子域名之間),因而發生了以下狀況:

  • 若是用戶訪問的網站爲www.a.com,然後端的api域名爲api.a.com。那麼在www.a.com下,前端拿不到api.a.com的Cookie,也就沒法完成雙重Cookie認證。
  • 因而這個認證Cookie必須被種在a.com下,這樣每一個子域均可以訪問。
  • 任何一個子域均可以修改a.com下的Cookie。
  • 某個子域名存在漏洞被XSS攻擊(例如upload.a.com)。雖然這個子域下並無什麼值得竊取的信息。但攻擊者修改了a.com下的Cookie。
  • 攻擊者能夠直接使用本身配置的Cookie,對XSS中招的用戶再向www.a.com下,發起CSRF攻擊。

參考:前端安全系列(二):如何防止CSRF攻擊?

相關文章
相關標籤/搜索