讀者在看這篇文章之前,請先了解 Oauth2.0 的 Authorization Code 授權流程,可以看 Authorization Code 授權原理和實現方法
我們還是用 A 來代表合作方,用 B 來代表鑒權方。在授權流程中,A 發起授權時,會向 B 傳一個 state 參數,而 B 對這個參數只做一個事情,就是在 302 跳轉返回的時候把它原封不動的返回。為什么要這么做呢?這背后是 CSRF 攻擊。
攻擊的流程是這樣的:
1,攻擊者訪問 A,通過點擊,觸發授權流程
2,攻擊者在本地設置代理,用於攔截瀏覽器的請求
3,攻擊者繼續完成授權流程,這時 B 會產生一個 code,並通過 redirect_uri 跳轉到 A,嘗試把 code 帶給 A
4,攻擊者攔截掉這個 302 跳轉,拿到 url,里面有 code 參數
5,攻擊者通過某種方式,誘騙真正的用戶點擊或觸發這個 url
6,A 收到 code,於是去兌換 access token,成功后把 access token 和用戶關聯起來。然而,實際上這個 access token 並不是用戶自己的,而是攻擊者的
到這里攻擊完成。這種手法常常用來攻擊第三方登錄功能。因為第三方登錄通常是用 Oauth2.0 實現的。其正常流程為:
1,用戶在 A 點擊第三方登錄按鈕,跳到 B 的授權頁面
2,用戶完成授權,B 跳轉回 A,帶上 code
3,A 用 code 去兌換 access token,然后再用 access token 去調 B 的api,取到 B_userid
4,A 做一個綁定,把用戶在 A 的當前賬號和 B 賬號綁定起來,即 B_userid -> A_userid
5,下次用戶再用 B_userid 登錄,A 就知道查到對應的 A_userid,於是實現了第三方登錄
被攻擊者攻擊了之后,B_userid -> A_userid 這個關系被篡改掉了,里面的 B_userid 被改成了攻擊者的 B 賬號,而不是用戶的 B 賬號。也就是說,下次攻擊者在 A 點第三方登錄,然后登錄自己的 B 賬號,再進到 A 里面,就能登錄進用戶的 A 賬號了。
用圖說明:
正常情況下,第三方登錄做的是:
被攻擊者經過這樣操作后,就變成:
仔細分析這種攻擊的核心關鍵特征,就是發起授權的用戶(攻擊者)和最后進行綁定的用戶(真實用戶)不是同一個人。那有沒有辦法在綁定的時候檢查一下呢?
可以的,state 參數就是用來做這個的。它本質上相當於一個一次性的臨時身份證,A 調起授權流程時,為當前登錄的用戶(此時是攻擊者)生成一個隨機字符串,作為 state 的值傳遞給 B,B 302 返回時,把 state 原封不動的返回。由於攻擊者進行攔截並誘導真實用戶點擊,此時當前登錄的用戶變成了真實用戶。但是攻擊者不知道真實用戶的臨時身份證,所以無法偽造。那么 A 在綁定的時候就可以查到 state 對應的是攻擊者的賬戶,而不是真實用戶的賬戶,於是拒絕做綁定。
有問題可以直接評論。