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)