目錄
一、csrf跨站請求偽造詳解????????
二、csrf跨域請求偽造
【1】正常服務端
【2】釣魚服務端
三、csrf校驗
【介紹】
form表單中進行csrf校驗:
【1】form表單如何校驗
【2】ajax如何校驗
四、csrf相關裝飾器
【1】csrf_protect裝飾器:
【2】csrf_exempt裝飾器:
【3】FBV中使用上述裝飾器
【4】CBV中使用上述裝飾器
(1)??csrf_protect
(2)??csrf_exempt方法
一、csrf跨站請求偽造詳解????????
- CSRF(Cross-Site Request Forgery)跨站請求偽造是一種常見的網絡攻擊方式。
- 攻擊者通過誘導受害者訪問惡意網站或點擊惡意鏈接
- 將惡意請求發送到目標網站上
- 利用受害者在目標網站中已登錄的身份來執行某些操作
- 從而達到攻擊的目的。
- 舉個例子
- 假設受害者在一家網銀網站上登錄賬戶,然后繼續瀏覽其他網頁。
- 同時,攻擊者通過電子郵件等方式向受害者發送了一封包含惡意鏈接的郵件。
- 當受害者點擊該鏈接時,潛在的威脅就會變得非常現實。
- 該鏈接指向一個由攻擊者操縱的網站,該網站上的惡意代碼會自動向網銀網站發送一個請求,請求轉賬到攻擊者的賬戶。
- 由于受害者在網銀網站中已經登錄,所以該請求會被認為是合法的,這樣攻擊者就可以成功地進行轉賬操作。
- 要保護自己免受CSRF攻擊,網站開發者可以采取以下措施:
- 使用CSRF令牌:
- 在用戶的請求中添加隨機生成的令牌,并將該令牌保存在用戶會話中。
- 每次提交請求時都會驗證該令牌,以確保請求是合法的。
- 啟用SameSite屬性:
- 將Cookie的SameSite屬性設置為Strict或Lax,以限制跨站請求。
- 這可以在一定程度上緩解CSRF攻擊。
- 嚴格驗證請求來源:
- 服務器端可以驗證請求的來源是否為預期的網站域名
- 例如檢查HTTP Referer頭部。
- 使用驗證碼:
- 在敏感操作(如轉賬、更改密碼等)上使用驗證碼
- 增加用戶身份驗證的防護。
- 使用CSRF令牌:
二、csrf跨域請求偽造
- 釣魚網站
- 搭建一個類似正規網站的頁面
- 用戶點擊網站鏈接,給某個用戶打錢
- 打錢的操作確確實實提交給了中國銀行的系統,用戶的錢也確實減少
- 但是唯一不同的是,賬戶打錢的賬戶不是用戶想要打錢的目標賬戶,變成了其他用戶
- 內部本質
- 在釣魚網站的頁面針對對方賬戶,只給用戶提供一個沒有name屬性的普通input框
- 然后在內部隱藏一個已經寫好帶有name屬性的input框
- 如何避免上面的問題
- csrf跨域請求偽造校驗
- 網站在給用戶返回一個具有提交數據功能的頁面的時候會給這個頁面加一個唯一標識
- 當這個頁面后端發送post請求的時候,我們后端會先校驗唯一標識
- 如果成功則正常執行
- 如果唯一標識不符合則拒絕連接(403 forbidden)
- csrf跨域請求偽造校驗
【1】正常服務端
- 前端
<h1>這是正規的網站</h1><form action="" method="post"><p>當前賬戶 :>>>> <input type="text" name="start_user"></p><p>目標賬戶 :>>>> <input type="text" name="end_user"></p><p>轉賬金額 :>>>> <input type="text" name="money"></p><input type="submit">
</form>
- 后端?
def transform_normal(request):if request.method == "POST":user_start = request.POST.get("start_user")user_end = request.POST.get("end_user")money = request.POST.get("money")return HttpResponse(f"當前賬戶 :>>> {user_start} 向目標用戶 :>>> {user_end} 轉賬了 :>>> {money}")return render(request, 'transform_normal.html')
?【2】釣魚服務端
- 前端
<h1>這是釣魚的網站</h1><form action="http://127.0.0.1:8000/transform_normal/" method="post"><p>當前賬戶 :>>>> <input type="text" name="start_user" ></p><p>目標賬戶 :>>>> <input type="text"></p><p><input type="text" name="end_user" value="Hopes" style="display: none"></p><p>轉賬金額 :>>>> <input type="text" name="money"></p><input type="submit">
</form>
- 后端
def transform_normal(request):if request.method == "POST":user_start = request.POST.get("start_user")user_end = request.POST.get("end_user")money = request.POST.get("money")return HttpResponse(f"當前賬戶 :>>> {user_start} 向目標用戶 :>>> {user_end} 轉賬了 :>>> {money}")return render(request, 'transform_normal.html')
三、csrf校驗
【介紹】
- csrf校驗是一種用于防止跨站請求偽造(Cross-Site Request Forgery)攻擊的安全措施
form表單中進行csrf校驗:
添加CSRF Token字段:
- 在form表單中添加一個隱藏字段,用于存儲CSRF Token的值。
- 后端服務器在渲染表單時生成一個CSRF Token,并將其存儲在會話中或者以其他方式關聯到當前用戶。
- 當用戶提交表單時,前端將CSRF Token的值包含在請求中。
- 后端在驗證表單數據時,檢查請求中的CSRF Token是否與存儲的Token匹配,如果不匹配,則拒絕請求。
設置Cookie:
- 后端服務器在渲染表單時,在客戶端設置一個包含隨機生成的CSRF Token的Cookie。
- 當用戶提交表單時,表單數據會被一同發送到服務器,并自動包含該Cookie。
- 后端在驗證表單數據時,檢查請求中的CSRF Token是否與Cookie中的值匹配,如果不匹配,則拒絕請求。
雙重Cookie校驗:
- 后端服務器在渲染表單時,在Cookie中設置一個隨機生成的CSRF Token,并將其存儲在會話中或以其他方式關聯到當前用戶。
- 當用戶提交表單時,表單數據會被一同發送到服務器,請求頭或請求參數中攜帶一個包含CSRF Token的自定義字段。
- 后端在驗證表單數據時,同時檢查請求中的CSRF Token和Cookie中的值是否匹配,如果不匹配,則拒絕請求。
【1】form表單如何校驗
- 在form表單上面加上
csrf_token
{% csrf_token %}
<form action="" method="post"><p>username:<input type="text" name="username"></p><p>transfer_user<input type="password" name="password"></p><p>money<input type="text" name="money"></p><input type="submit">
</form>
- 在頁面標簽中會自動出現一個標簽
<input type="hidden" name="csrfmiddlewaretoken" value="zQaNPZsy1tVmLdqC7GIDOOOfR7yT9YfO58lJ5yrjZfTw2edZTrVYUllOVMnkwXKe">
【2】ajax如何校驗
- 方式一
- 利用標簽查找獲取頁面上的隨機字符串
- 鍵必須叫?
csrfmiddlewaretoken
<button id="b1">ajax請求提交</button><script>$("#b1").click(function () {$.ajax({url: '',type: 'post',// (1) 利用標簽查找獲取頁面上的隨機字符串data: {"username": "dream","csrfmiddlewaretoken":$('[csrfmiddlewaretoken]').val()},success: function () {}})})
</script>
- 方式二
- 利用模板語法進行快捷引入
<button id="b1">ajax請求提交</button><script>$("#b1").click(function () {$.ajax({url: '',type: 'post',// (2) 利用模板語法提供的快捷書寫data: {"username": "dream", "csrfmiddlewaretoken": "{{ csrf_token }}"},success: function () {}})})
</script>
- 方式三
- 定義一個js文件并引入
- 導入該配置文件之前,需要先導入jQuery,因為這個配置文件內的內容是基于jQuery來實現的
function getCookie(name) {var cookieValue = null;if (document.cookie && document.cookie !== '') {var cookies = document.cookie.split(';');for (var i = 0; i < cookies.length; i++) {var cookie = jQuery.trim(cookies[i]);// Does this cookie string begin with the name we want?if (cookie.substring(0, name.length + 1) === (name + '=')) {cookieValue = decodeURIComponent(cookie.substring(name.length + 1));break;}}}return cookieValue;
}
var csrftoken = getCookie('csrftoken');function csrfSafeMethod(method) {// these HTTP methods do not require CSRF protectionreturn (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}$.ajaxSetup({beforeSend: function (xhr, settings) {if (!csrfSafeMethod(settings.type) && !this.crossDomain) {xhr.setRequestHeader("X-CSRFToken", csrftoken);}}
});
<button id="b1">ajax請求提交</button><script>$("#b1").click(function () {$.ajax({url: '',type: 'post',// (3) 定義外部js文件并引入到本地data: {"username": "dream"},success: function () {}})})
</script>
四、csrf相關裝飾器
- 網站整體部分校驗csrf,部分不校驗csrf
- 網站整體全部校驗csrf,部分不校驗csrf
【1】csrf_protect裝飾器:
- csrf_protect裝飾器用于需要進行CSRF保護的視圖函數或類視圖。
- 當一個視圖被csrf_protect裝飾器修飾時,Django會對該視圖接收到的所有POST、PUT、DELETE等非安全HTTP方法的請求進行CSRF校驗。
- 如果請求中沒有有效的CSRF令牌或令牌校驗失敗,Django將返回403 Forbidden響應。
【2】csrf_exempt裝飾器:
- csrf_exempt裝飾器用于不需要進行CSRF保護的視圖函數或類視圖。
- 當一個視圖被csrf_exempt裝飾器修飾時,Django將不會對該視圖接收到的任何請求進行CSRF校驗。
- 這個裝飾器主要用于一些特殊情況,比如與第三方系統進行集成、開放API接口等。
【3】FBV中使用上述裝飾器
from django.views.decorators.csrf import csrf_protect, csrf_exempt
'''
csrf_protect 需要校驗
csrf_exempt 忽視校驗
'''
-
當我們沒有注釋掉
csrf校驗中間件
的時候,可以在函數頭上加上?@csrf_exempt
?忽視校驗 -
當我們注釋掉
csrf校驗中間件
的時候,可以在函數頭上加上?@csrf_protect
?強制啟動校驗
【4】CBV中使用上述裝飾器
from django.views.decorators.csrf import csrf_protect, csrf_exempt
'''
csrf_protect 需要校驗針對 csrf_protect 符合之前的裝飾器的三種用法
csrf_exempt 忽視校驗針對 csrf_exempt 只能給 dispatch 方法加才有效
'''
(1)??csrf_protect
- (1) 方式一
- 給指定方法加
@method_decorator
- 給指定方法加
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decoratorclass MyCsrf(View):def get(self, request):return HttpResponse("get")@method_decorator(csrf_protect)def post(self, request):return HttpResponse("post")
- (2) 方式二
- 給類加然后指明方法?
@method_decorator
- 給類加然后指明方法?
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator@method_decorator(csrf_protect)
class MyCsrf(View):def get(self, request):return HttpResponse("get")def post(self, request):return HttpResponse("post")
- (3) 方式三
- 重寫?
dispatch
?方法
- 重寫?
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decoratorclass MyCsrf(View):@method_decorator(csrf_protect)def dispatch(self, request, *args, **kwargs):return super(MyCsrf, self).dispatch(request, *args, **kwargs)def get(self, request):return HttpResponse("get")def post(self, request):return HttpResponse("post")
(2)??csrf_exempt
方法
- 只有重寫?
dispatch
方法 有效
from django.views import View
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decoratorclass MyCsrf(View):@method_decorator(csrf_exempt)def dispatch(self, request, *args, **kwargs):return super(MyCsrf, self).dispatch(request, *args, **kwargs)def get(self, request):return HttpResponse("get")def post(self, request):return HttpResponse("post")