Flask框架——CSRF保護


CSRF攻擊

CSRF全拼爲Cross Site Request Forgery,譯爲跨站請求僞造。
CSRF指攻擊者盜用了你的身份,以你的名義發送惡意請求。
包括:以你名義發送郵件,發消息,盜取你的賬號,甚至於購買商品,虛擬貨幣轉賬…
造成的問題:個人隱私泄露以及財產安全。

攻擊示意圖:
在這裏插入圖片描述

如何防禦CSRF攻擊

csrf_token服務器內部校驗過程:
表單提交
1.在表單中攜帶,隱藏的csrf_token,加密的 (自己設置)
2.在cookie中,設置一個sessionID (服務器設置)
在提交的時候,服務器校驗過程:
(1)取出表單中的csrf_token, 使用SECRET_KEY,進行解密, 得到未加密的csrf_token
(2)通過sessionID取出,服務器內部的session空間中的,未加密的csrf_token,比較二者的值是否相等,如果相等則校驗通過

非表單提交, ajax提交
1.在headers中設置csrf_token,加密的 (自己設置), 來自於cookie中的 (我們自己設置的)
2.在cookie中,設置一個sessionID (服務器設置)
在提交的時候,服務器校驗過程:
(1)取出headers中的csrf_token, 使用SECRET_KEY,進行解密, 得到未加密的csrf_token
(2)通過sessionID取出,服務器內部的session空間中的,未加密的csrf_token,比較二者的值是否相等,如果相等則校驗通過

Flask框架中的CSRF保護機制

csrf_token: 爲了解決跨站請求僞造,⽽定義的變量
flask中提供了模塊flask_wtf⾥⾯提供了⼀個類CSRFProtect來保護
使⽤流程:
1.導⼊模塊: from flask_wtf import CSRFProtect
2.使⽤CSRFProtect(app), 保護應⽤程序
3.在表單中,使⽤csrf_token(), ⾃動⽣成⼀個csrf_token值,並且這個值是加密的,需要設置
SECRET_KEY
4.csrfprotect保護的時候對以下請求⽅式做校驗:‘POST’, ‘PUT’, ‘PATCH’, ‘DELETE’
代碼實現:
在html模板文件中表單提交裏需要加上一個隱藏的字段csrf_token
在這裏插入圖片描述

from flask import Flask,render_template,request
from flask_wtf import CSRFProtect

app = Flask(__name__)

app.config["SECRET_KEY"] = "fjdkfkdjfdk"

CSRFProtect(app)

@app.route('/')
def index():

    return render_template("file08index.html")

@app.route('/register',methods=["POST"])
def register():

    #1.獲取參數
    username = request.form.get("username")
    password = request.form.get("password")
    repassword = request.form.get("repassword")

    #2.校驗,爲空校驗
    if not all([username,password,repassword]):
        return "參數填寫不完整"

    #3.密碼需要一致
    if password != repassword:
        return "密碼不一致"


    return "註冊成功"

if __name__ == '__main__':
    app.run(debug=True)

具體實現方法(手動添加):

@app.route('/', methods=["POST", "GET"])
def index():
    if request.method == "POST":
        # 取到表單中提交上來的參數
        username = request.form.get("username")
        password = request.form.get("password")

        if not all([username, password]):
            print('參數錯誤')
        else:
            print(username, password)
            if username == 'laowang' and password == '1234':
                # 狀態保持,設置用戶名到cookie中表示登錄成功
                response = redirect(url_for('transfer'))
                response.set_cookie('username', username)
                return response
            else:
                print('密碼錯誤')

    return render_template('temp_login.html')


#轉賬頁面
@app.route('/transfer', methods=["POST", "GET"])
def transfer():
    # 從cookie中取到用戶名
    username = request.cookies.get('username', None)
    # 如果沒有取到,代表沒有登錄
    if not username:
        return redirect(url_for('index'))

    if request.method == "POST":
        to_account = request.form.get("to_account")
        money = request.form.get("money")


        # 取到表單中的token
        form_csrf_token = request.form.get('csrf_token')
        # cookie中的token
        cookie_csrf_token = request.cookies.get('csrf_token', "")

        # 做校驗。如果校驗成功,再進行轉賬邏輯
        if form_csrf_token != cookie_csrf_token:
            return "你是壞蛋,非法請求"



        print('假裝執行轉賬操作,將當前登錄用戶的錢轉賬到指定賬戶')
        return '轉賬 %s 元到賬號 %s 成功' % (money, to_account)



    csrf_token = generate_csrf()
    # 渲染轉換頁面,表單中設置csrf_token
    response = make_response(render_template('temp_transfer.html', csrf_token=csrf_token))
    # 往cookie中添加csrf_token
    response.set_cookie('csrf_token', csrf_token)



    return response


# 生成 csrf_token
def generate_csrf():
    return bytes.decode(base64.b64encode(os.urandom(48)))


if __name__ == '__main__':
    app.run(debug=True, port=9000)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章