天天看點

Python學習筆記:6.3.11 csrf攻擊與防範

前言:本文是學習網易微專業的《python全棧工程師 - Flask進階建站》課程的筆記,歡迎學習交流。同時感謝老師們的精彩傳授!

一、課程目标

  • 什麼是CSRF
  • 表單的CSRF保護
  • AJAX的CSRF保護

二、詳情解讀

2.1.CSRF跨站攻擊

2.1.1.什麼是跨站攻擊

在會員管理中,要删除一個會員隻要通路

127.0.0.1:5000/admin/user/delete/1

有人會認為:這個連結你一定要登入才能通路,怎麼會有安全性問題呢

攻擊行為: 想辦法給管理者發一條删除連結,比如在圖檔中放置這個連結

Python學習筆記:6.3.11 csrf攻擊與防範

管理者如果在登入狀态下點選此圖檔就會将員删除,攻擊成功。

這種攻擊行為稱為:

Cross-SiteRequestForgecy

- 跨站請求僞造,簡稱:

CSRF

如果改成表單送出會不會避免這個問題?

問題同樣存在,對于伺服器來說,如同不能識别身份一樣,也沒能識别資料的來源。

Python學習筆記:6.3.11 csrf攻擊與防範

B站一樣可以送出登入資料完成登入,B站如果是一個僞站,那麼使用者就可能在不知情的情況下完成登入,進而帳号密碼被盜。

Python學習筆記:6.3.11 csrf攻擊與防範

是以表單也不是安全的,必須想辦法在連結或者表單上做識别符号,就與使用者的身份識别一樣,給每個表單或者連結加上身份。通常用

csrf-token

辨別符來表示這個身份

2.2.表單的CSRF保護

2.2.1.CSRF保護

flask_wtf

提供了

csrf

防範能力,預設建立一個包含

csrf_token

值的隐藏域,

當使用

form.validate_on_submit()

方法驗證資料時,就會用

session

中的值與

csrf_token

的值進行比較,

如果兩者不一緻,那麼就認為表單是僞造的,拒絕處理。

2.3.ajax的CSRF保護

Step1

:

from flask_wtf.csrf import CSRFProtect
           

Step2

:建立執行個體

Step3

app

執行個體參數配置:

Step4

:在模版中使用

{{ csrf_token() }}

可以獲得

token

我們首先将通過連結删除修改為通過

ajax

删除

1.請求方式修改為

post

2.在

ajax

中設定:

beforeSend: function(xhr) {
	xhr.setRequestHeader("X-CSRFToken", {{ csrf_token() }})
}
           

3.視圖函數中使用

csrf.protect()

檢驗

csrf_token

值:

def deleteUser():
	csrf.protect()
           

實操:

Step1

:在

libs.py

檔案中導入

csrfprotect

并建立執行個體

.
.
.
from functools import wraps
# 新增下面這一行
from flask_wtf.csrf import CSRFProtect
from flask_ckeditor import CKEditor

# 建立資料庫對象
# 這裡不用傳入app執行個體對象,因為這裡尚未建立app執行個體
db=SQLAlchemy()
# 新增下面這一行
csrf = CSRFProtect()
ckeditor = CKEditor()
.
.
.
           

Step2

:在

app.py

中導入

csrf

執行個體并初始化配置

from flask import Flask, render_template
from flask import request, redirect, url_for
# 導入下面一行中的csrf
from libs import db, ckeditor, csrf
from views.users import user_app
.
.
.
db.init_app(app)
ckeditor.init_app(app)
# 下面這一行初始化csrf
csrf.init_app(app)
.
.
.
           

Step3

:在

templates/login.html

中測試一下

.
.
.
				</div>
			</div>
			<!-- 添加下面這個csrf_token() -->
			{{ csrf_token() }}
		</div>
		{%  endblock %}
	</body>
</html>
           

第三步這裡,登入頁面會輸出一串字元串

Python學習筆記:6.3.11 csrf攻擊與防範

Step4

:修改

templates/user/user_list.html

中的删除使用者連結,并新增

delUser()

函數:

.
.
.
<a href="{{ url_for(" target="_blank" rel="external nofollow" user_app.editUser", user_id=user.id) }}">修改</a>
<a href="#" onclick="delUser({{ user.id }})">删除</a>
.
.
.
<script>
function delUser(userid) {
     $.ajax({
         type: 'post',
         url: '{{ url_for("admin_app.deleteUser")}}',
         data: { user_id: userid},
         dataType: 'json',
         beforeSend: function(xhr) {
             xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token() }}')
         },
         success: function(data) {
             if (data.result == 'success') {
                 $('#user_' + userid).innerHTML = "<tr>" +
                 "<td colspan='6'>" + "删除成功" + "</td>" + "</tr>"
             } else {
                 alert('删除過程發生錯誤,請重新嘗試')
             }
         }
     })
 }
</script>
{% endblock %}

</body>
</html>
           

Step5

:修改

admin/user.py

内容:

.
.
.
# 導入csrf
from libs import db, csrf
.
.
.
# 根據使用者id删除使用者, 新增methods
@admin_app.route('/user/delete', methods=['POST'])
def deleteUser():
	# 新增下面這一行
    csrf.protect()
    user_id = int(request.form.get('user_id'))
    user = User.query.get(user_id)
    message = {}
    try:
        db.session.delete(user)
        db.session.commit()
    except:
        message['result'] = 'fail'
    else:
        message['result'] = 'success'
    return json.dumps(message)
.
.
.
           

三、課程小結

  • csrf

    跨站攻擊
  • csrf_token

  • ajax

    發送

    csrf_token

繼續閱讀