登錄流程及防止跨域偽造攻擊
第 1 步
瀏覽器使用 POST 方法發(fā)送登錄請(qǐng)求。
服務(wù)器收到瀏覽器發(fā)來(lái)的請(qǐng)求,F(xiàn)lask 框架在處理請(qǐng)求的時(shí)候,利用 Flask-WTF 插件生成一個(gè)隨機(jī)的字符串,下圖所示:

這個(gè)就是 csrf_token 字段,它會(huì)經(jīng)過(guò) A 令牌生成器生成一個(gè)令牌塞到響應(yīng) body 的表單的隱藏域里。
第 2 步
每個(gè)請(qǐng)求都由一個(gè)單獨(dú)的線程處理,這個(gè)線程會(huì)創(chuàng)建一個(gè)請(qǐng)求上下文對(duì)象,它有個(gè) session 屬性,屬性值是類字典對(duì)象。
捎帶腳,這個(gè)「 csrf_token 字段及其值」會(huì)作為「請(qǐng)求上下文對(duì)象的 session 屬性值」的鍵值對(duì),這個(gè)字典的鍵值對(duì)可能很多,例如 _id (它是根據(jù) IP 地址和 USER_AGENT 生成的 128 位字符串)、_user_id 是用戶存在數(shù)據(jù)庫(kù)里的主鍵等等。
先瞎編一個(gè)字典:

然后有一個(gè) B 令牌生成器將「請(qǐng)求對(duì)象的 session 屬性值」作為參數(shù)調(diào)用令牌生成器的 dumps 方法,就生成了一個(gè)字符串,它就是 session :

這個(gè) session 字符串會(huì)被扔到響應(yīng)對(duì)象的頭部字典的 Set-Cookie 鍵中,粗略代碼如下:
response.headers.add('Set-Cookie', b'session={}'.format(session))
響應(yīng)對(duì)象傳回瀏覽器,瀏覽器設(shè)置 Cookies 后,Cookies 鍵值對(duì)中就有了 session 字段。
額外說(shuō)明:瀏覽器首次訪問(wèn)網(wǎng)站時(shí),F(xiàn)lask Web 應(yīng)用也會(huì)在響應(yīng)對(duì)象中提供一個(gè) session ,如果響應(yīng) body 有表單,也會(huì)在隱藏域中提供 csrf_token 。
第 3 步
瀏覽器再次發(fā)送了一個(gè)請(qǐng)求,假設(shè)是帶表單的 POST 請(qǐng)求,修改用戶信息之類的操作。
這個(gè)請(qǐng)求對(duì)象里就攜帶了 cookies 和表單,表單里有 csrf_token 的加密令牌。
服務(wù)器收到請(qǐng)求后,把表單隱藏域中的值拿出來(lái)使用 A 令牌生成器解密并賦值給一個(gè)變量,我們假設(shè)它是 c1 。
把 cookies 里的 session 字段的值拿出來(lái),使用 B 令牌生成器解密得到字典:

然后從中拿出 csrf_token 字段的值跟 c1 比較,就可以判斷這個(gè)請(qǐng)求了。
如果壞人使用「跨域偽造攻擊」,可以得到用戶瀏覽器上的 cookies ,也就得到了 session ,但它得不到表單隱藏域 csrf_token ,這個(gè) csrf_token 跟 session 是一套。
防止 CSRF 跨域偽造攻擊
用戶訪問(wèn)「某某銀行」的網(wǎng)站,登錄后,瀏覽器保存帶有 session 的 Cookies
而 csrf_token 呢,它作為一個(gè) 40 位的字符串,會(huì)被加密成一個(gè)更復(fù)雜的字符串
這個(gè)字符串被放到響應(yīng)對(duì)象的 body 中的表單的隱藏域里頭,返回給瀏覽器
也就是說(shuō)只有包含表單的頁(yè)面才有這個(gè) csrf_token ,下圖所示:

- 現(xiàn)在攻擊者誘導(dǎo)用戶訪問(wèn)釣魚網(wǎng)站,釣魚網(wǎng)站獲取用戶的 Cookie
- 然后自動(dòng)使用 POST 方法訪問(wèn)地址,這個(gè)地址就是轉(zhuǎn)賬請(qǐng)求,這個(gè)請(qǐng)求會(huì)帶上偷來(lái)的 Cookie
- 雖然有偷來(lái)的 Cookie ,但沒(méi)有表單的隱藏字段 csrf_token ,所以請(qǐng)求會(huì)失敗