flask總結05(在 Flask 項目中解決 CSRF 攻擊)
一:安裝 flask_wtf
pip install flask_wtf
二:設置應用程序的 secret_key,用於加密生成的 csrf_token 的值
# session加密的時候已經配置過了.如果沒有在配置項中設置,則如下: app.secret_key = "#此處可以寫隨機字符串#"
三:導入 flask_wtf.csrf 中的 CSRFProtect 類,進行初始化,並在初始化的時候關聯 app
from flask.ext.wtf import CSRFProtect
CSRFProtect(app)
四:在表單中使用 CSRF 令牌:
<form method="post" action="/"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" /> </form>
五:scrf的過程理解
代碼顯示方法不被允許的代碼
#manage.py
from flask import Flask, render_template, request, g from settings.dev import DevConfig from flask.ext.wtf import CSRFProtect app = Flask(__name__, template_folder="templates", static_folder="static") app.config.from_object(DevConfig) CSRFProtect(app) # @app.route("/csrf_test", methods=["get", "post"]) @app.route("/csrf_test") def index(): if request.method == "GET": return render_template("form.html") else: print(request.form) return "ok" if __name__ == "__main__": app.run()
templates下的form.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf案例</title> </head> <body> <form action="" method="post"> 賬號:<input type="text" name="username"><br><br> 密碼:<input type="password" name="password"><br><br> <input type="submit" value="提交"> </form> </body> </html>
運行后顯示的結果是:
然后修改manage.py中的代碼,添加
@app.route("/csrf_test", methods=["get", "post"])
代碼如下:
from flask import Flask, render_template, request, g from settings.dev import DevConfig from flask.ext.wtf import CSRFProtect app = Flask(__name__, template_folder="templates", static_folder="static") app.config.from_object(DevConfig) CSRFProtect(app) @app.route("/csrf_test", methods=["get", "post"]) def index(): if request.method == "GET": return render_template("form.html") else: print(request.form) return "ok" if __name__ == "__main__": app.run()
再次執行:並且提交:
說明需要在html文檔中添加:csrf_token
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
修改后的代碼是:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf案例</title> </head> <body> <form action="" method="post"> <input type="hidden" name="csrf_token" value="{{csrf_token()}}"> 賬號:<input type="text" name="username"><br><br> 密碼:<input type="password" name="password"><br><br> <input type="submit" value="提交"> </form> </body> </html>
運行后的結果顯示:
flask——CSRFToken保護
根據 csrf_token 校驗原理,具體操作步驟有以下幾步:
1.后端生成 csrf_token 的值,在前端請求登錄或者注冊界面的時候將值傳給前端,傳給前端的方式可能有以下兩種:
在模板中的 From 表單中添加隱藏字段
將 csrf_token 使用 cookie 的方式傳給前端
2.在前端發起請求時,在表單或者在請求頭中帶上指定的 csrf_token
3.后端在接受到請求之后,取到前端發送過來的 csrf_token,與第1步生成的 csrf_token 的值進行校驗
4.如果校驗對 csrf_token 一致,則代表是正常的請求,否則可能是偽造請求,不予通過
而在 Flask 中,CSRFProtect 這個類專門只對指定 app 進行 csrf_token 校驗操作,所以開發者需要做以下幾件事情:
生成 csrf_token 的值
將 csrf_token 的值傳給前端瀏覽器
在前端請求時帶上 csrf_token 值
生成 csrf_token 的值
# 導入生成 csrf_token 值的函數 from flask_wtf.csrf import generate_csrf # 調用函數生成 csrf_token csrf_token = generate_csrf()
將 csrf_token 的值傳給前端瀏覽器
實現思路:可以在請求勾子函數中完成此邏輯
@app.after_request def after_request(response): # 調用函數生成 csrf_token csrf_token = generate_csrf() # 通過 cookie 將值傳給前端 response.set_cookie("csrf_token", csrf_token) return response
在前端請求時帶上 csrf_token 值
根據登錄和注冊的業務邏輯,當前采用的是 ajax 請求
所以在提交登錄或者注冊請求時,需要在請求頭中添加 X-CSRFToken 的鍵值對
$.ajax({ url:"/passport/register", type: "post", headers: { "X-CSRFToken": getCookie("csrf_token")#get_Cookie為自定義函數 }, data: JSON.stringify(params), contentType: "application/json", success: function (resp) { if (resp.errno == "0"){ // 刷新當前界面 location.reload() }else { $("#register-password-err").html(resp.errmsg) $("#register-password-err").show() } } })
flask csrf保護的使用技巧
CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。 ——百度百科
網上關於csrf攻擊的一個最典型的例子是銀行通過url+參數轉錢的問題,很好理解。
flask 作為一個強帶的web微框架,自然也是支持防范csrf攻擊的。
通過Flask-WTF來保護表單免受CSRF攻擊
何為Flask-WTF
簡單說來,使用它可以方便我們構建表單和驗證表單,具體用法這里不做贅述
怎么開啟保護?
極少的配置,一個應用令牌:
app.config['SECRET_KEY'] = 'you can't know' 或csrf專用令牌 app.config['WTF_CSRF_SECRET_KEY'] = 'IT 666 to 709 kill pic'
Flask-WTF默認是開啟CSRF保護的,你需要的做的是在你的模板中表單一欄加入:
{{ form.csrf_token }}
或者
{{ form.hidden_tag() }}
這樣,csrf保護已經開啟。如若你沒有上面的代碼,提交表單會無法通過form.validate_on_submit()
,錯誤為
{'csrf_token': ['The CSRF token is missing.']},但這並不會導致http錯誤,僅是無法通過驗證。
關閉保護
自然,我們很可能有的表單不需要保護,那么,以下三種:
全局禁用:app.config中設置WTF_CSRF_ENABLED = False
單個表單禁用:生成表單時加入參數form = Form(csrf_enabled=False)
不使用Flask-WTF…啊啊,這個很好理解
http://docs.jinkan.org/docs/flask-wtf/from.html
flask 內置的保護機制
有些時候,我根本就用不到Flask-WTF,那么我可以使用flask自身提供的保護機制。
開啟保護
要開啟csrf攻擊保護,需要一下幾個步驟。
from flask_wtf.csrf import CSRFProtect app.config['SECRET_KEY'] = 'you never guess' CSRFProtect(app)
主要為:導入方法,設置密鑰,進行保護。
這時候對於一個普通的form,如果你沒有
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
flask會拋出http錯誤。
臨時關閉保護
那么,如何臨時關閉csrf保護呢。
上面的代碼做修改:
去掉 CSRFProtect(app) 改為 csrf = CSRFProtect() if __name__ == '__main__':中加入 csrf.init_app(app) 在不需要保護的路由上當加上: @csrf.exempt
如此,臨時關閉了csrf。