登錄流程及防止跨域偽造攻擊
第 1 步
瀏覽器使用 POST 方法發(fā)送登錄請求瓶逃。
服務器收到瀏覽器發(fā)來的請求箩朴,Flask 框架在處理請求的時候芹缔,利用 Flask-WTF 插件生成一個隨機的字符串养匈,下圖所示:
這個就是 csrf_token
字段廉白,它會經過 A 令牌生成器生成一個令牌塞到響應 body 的表單的隱藏域里。
第 2 步
每個請求都由一個單獨的線程處理乖寒,這個線程會創(chuàng)建一個請求上下文對象,它有個 session 屬性院溺,屬性值是類字典對象楣嘁。
捎帶腳,這個「 csrf_token
字段及其值」會作為「請求上下文對象的 session 屬性值」的鍵值對珍逸,這個字典的鍵值對可能很多逐虚,例如 _id
(它是根據 IP 地址和 USER_AGENT 生成的 128 位字符串)、_user_id
是用戶存在數據庫里的主鍵等等谆膳。
先瞎編一個字典:
然后有一個 B 令牌生成器將「請求對象的 session 屬性值」作為參數調用令牌生成器的 dumps 方法叭爱,就生成了一個字符串,它就是 session
:
這個 session 字符串會被扔到響應對象的頭部字典的 Set-Cookie 鍵中漱病,粗略代碼如下:
response.headers.add('Set-Cookie', b'session={}'.format(session))
響應對象傳回瀏覽器买雾,瀏覽器設置 Cookies 后,Cookies 鍵值對中就有了 session 字段杨帽。
額外說明:瀏覽器首次訪問網站時漓穿,Flask Web 應用也會在響應對象中提供一個 session ,如果響應 body 有表單注盈,也會在隱藏域中提供 csrf_token 晃危。
第 3 步
瀏覽器再次發(fā)送了一個請求,假設是帶表單的 POST 請求老客,修改用戶信息之類的操作僚饭。
這個請求對象里就攜帶了 cookies 和表單震叮,表單里有 csrf_token 的加密令牌。
服務器收到請求后鳍鸵,把表單隱藏域中的值拿出來使用 A 令牌生成器解密并賦值給一個變量苇瓣,我們假設它是 c1 。
把 cookies 里的 session 字段的值拿出來权纤,使用 B 令牌生成器解密得到字典:
然后從中拿出 csrf_token 字段的值跟 c1 比較钓简,就可以判斷這個請求了。
如果壞人使用「跨域偽造攻擊」汹想,可以得到用戶瀏覽器上的 cookies 外邓,也就得到了 session ,但它得不到表單隱藏域 csrf_token 古掏,這個 csrf_token 跟 session 是一套损话。
防止 CSRF 跨域偽造攻擊
用戶訪問「某某銀行」的網站,登錄后槽唾,瀏覽器保存帶有 session 的 Cookies
而 csrf_token 呢丧枪,它作為一個 40 位的字符串,會被加密成一個更復雜的字符串
這個字符串被放到響應對象的 body 中的表單的隱藏域里頭庞萍,返回給瀏覽器
也就是說只有包含表單的頁面才有這個 csrf_token 拧烦,下圖所示:
- 現在攻擊者誘導用戶訪問釣魚網站,釣魚網站獲取用戶的 Cookie
- 然后自動使用 POST 方法訪問地址钝计,這個地址就是轉賬請求恋博,這個請求會帶上偷來的 Cookie
- 雖然有偷來的 Cookie ,但沒有表單的隱藏字段 csrf_token 私恬,所以請求會失敗