Django——CSRF防護

關於CSRF攻擊原理在上一篇博客已經有過說明,這篇主要介紹下Django關於開啓CSRF及CSRF工做機理。關於開啓防護有兩種,一種是全局開啓,另外一種是局部開啓。html

全局:前端

中間件 django.middleware.csrf.CsrfViewMiddlewarepython

局部:from django.views.decorators.csrf import csrf_exempt,csrf_protectjquery

  • 針對某一個函數視圖開啓(關閉)csrf防禦
  1. @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。
  2. @csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。
  • 針對某一個類視圖開啓csrf防禦
@method_decorator(csrf_protect)
class MyClassView(request):
    # 類視圖邏輯
    return render(request, "example.html")
  • 在template模版中,使用{% csrf_token %},去生成隨機的csrf token(key爲csrfmiddlewaretoken的隱藏字段)

運做機理

當前端發送一個post請求時,後端會校驗是否有一個csrf的隨機字符串,若是沒有就會報錯。一般前端會發送post請求無外兩種狀況,一種是form表單的請求,另外一種是Ajax請求。ajax

對於form表單請求,咱們一般是在表單下添加{% csrf_token %}來自動生成字段名爲csrfmiddlewaretoken,值爲一段長長的字符串。經過審查前端代碼,能夠發現表單下隱藏着下面一段代碼。django

對於Ajax請求,上面的字段就不能經過{% csrf_token %}這種方法了。咱們須要從本地瀏覽器的cookie中獲取。在cookie中這個字段名爲csrftoken,前端發過去的字段名爲X-CSRFtoken,後臺真正接收到的字段名變成了HTTP_X_CSRFTOKEN。後端

那爲何從Django的控制檯輸出會獲得HTTP_X_CSRFTOKEN呢?其實咱們前端的請求頭X-CSRFtoken發送到後臺以後,django會作一個名字處理,在原來的字段名前家一個HTTP_,而且將原來的小寫字符變成大寫的,「-」會處理成下劃線「_」,因此會有這兩個字段的不同。但本質上他們指向的都是同一個字符串。
            jquery的ajax請求中爲咱們封裝了一個方法:ajaxSetup,它能夠爲咱們全部的ajax請求作一個集體配置,因此咱們能夠進行以下改造,這樣無論你的ajax請求有多少,均可以很方便地進行csrf驗證了:瀏覽器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="POST">
        {% csrf_token %}
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="checkbox" name="rmb" value="1" /> 10s免登陸
        <input type="submit" value="提交" />
        <input id="btn" type="button" value="按鈕">
    </form>
 
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        var csrftoken = $.cookie('csrftoken');
        
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
 
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url:'/login/',
                    type:"POST",
                    data:{'username':'root','pwd':'123123'},
                    success:function (arg) {
                        
                    }
                })
            })
        });
    </script>
</body>
</html>
相關文章
相關標籤/搜索