Django之CBV装饰器、中间件、csrf 跨站请求伪造

一、CBV装饰器

要求:访问CBV函数视图需要先登录

1、含cookie的装饰器

# 登录认证装饰器cookie版
def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('username'):
            return func(request, *args, **kwargs)
        else:
            return redirect('/login1/')

    return inner

2、views 视图函数

需要导入method_decorator装饰器模块

第一种方式:在方法上加装饰器

from django.views import View

from django.utils.decorators import method_decorator

class Login(View):
    # 必须登录之后才能访问get访问
    @method_decorator(login_auth)
    def get(self, request):
        return HttpResponse("get")

    @method_decorator(login_auth)
    def post(self, request):
        return HttpResponse("post")

第二种方式:在类上加装饰器

from django.views import View
from django.utils.decorators import method_decorator

@method_decorator(login_auth, name='get')
@method_decorator(login_auth, name='post')
class Login(View):
    # 必须登录之后才能访问get访问
    def get(self, request):
        return HttpResponse("get")

    def post(self, request):
        return HttpResponse("post")

注意:第二个参数name=‘’, 跟的是方法名

第三种方式:重写View类的 dispatch方法

from django.views import View
from django.utils.decorators import method_decorator


class Login(View):
    @method_decorator(login_auth)
    def dispatch(self, request, *args, **kwargs):
        return super(Login, self).dispatch(request, *args, **kwargs)

    # 必须登录之后才能访问get访问
    def get(self, request):
        return HttpResponse("get")

    def post(self, request):
        return HttpResponse("post") 

二、中间件

1、默认的7个中间件的作用

1.  django.middleware.security.SecurityMiddleware:提供了一些安全性功能,如点击劫持(clickjacking)保护、XSS(跨站脚本)保护等。它会自动添加适当的HTTP头,以增强应用的安全性。

2. django.contrib.sessions.middleware.SessionMiddleware:处理(session\cookie)数据。它为每个用户提供一个独立的会话,可以在多个HTTP请求之间存储临时数据。

3. django.middleware.common.CommonMiddleware:处理一些常见的HTTP头,如Content-Type,以及处理URL尾部的斜杠,确保URL的一致性。

4. django.middleware.csrf.CsrfViewMiddleware:处理CSRF(跨站请求伪造)保护。它会检查POST、PUT、DELETE等非安全请求中的CSRF令牌,以防止CSRF攻击。

5. django.contrib.auth.middleware.AuthenticationMiddleware:处理用户认证。它会根据用户登录状态和会话信息将用户对象添加到每个请求中。

6. django.contrib.messages.middleware.MessageMiddleware:处理消息通知,如使用messages模块在请求之间传递消息。

7. django.middleware.clickjacking.XFrameOptionsMiddleware:提供点击劫持(clickjacking)保护。它设置X-Frame-Options HTTP头,指示浏览器是否允许在<frame>、<iframe>、<embed>或<object>中显示页面。

2、自定义中间件

中间件就是一个类,然后这个类都继承了 MiddlewareMixin

其中 process_request 和 process_response 方法比较重要,其他方法看需求使用如:process_view、process_template

class MyMiddleware1(MiddlewareMixin):
    def process_request(self, request):
        # IP限制
        # 
        print("我是第一个自定义的中间件process_request")

    def process_response(self, request, response):
        print("我是第一个自定义中间件的process_response")
        return response  # 每一个process_response都必须有返回值response


class MyMiddleware2(MiddlewareMixin):
    def process_request(self, request):
        print("我是第二个自定义的中间件process_request")

    def process_response(self, request, response):
        print("我是第二个自定义中间件的process_response")
        return response  # 每一个process_response都必须有返回值response

注意:自定义中间件步骤:

1. 在项目名下或者任意的应用名下创建一个文件夹

2. 在这个文件夹下面创建一个py文件

3. 在该py文件中写一个自定义的类必须要继承MiddlewareMixin

4. 写完之后紧接着一定要去配置文件中注册中间件

3、中间件的执行顺序

执行顺序按照在MIDDLEWARE中定义的顺序,从上到下执行。

当一个请求进来时,这些中间件会依照这个顺序逐个处理请求(process_request)

然后在请求返回响应阶段按照相反的顺序逐个处理响应(process_re)

三、csrf跨站请求

1、CSRF(Cross-Site Request Forgery)机制

Django中的CSRF保护机制确实会使用cookie和session来进行管理。

当在HTML页面的form表单中使用{% csrf_token %}模板标签时,Django会在生成的表单中添加一个隐藏字段(通常名为csrfmiddlewaretoken),并将这个字段的值设置为一个随机生成的CSRF令牌。

具体来说,CSRF保护的工作流程如下:

  1. 生成CSRF令牌:在每个页面加载时,Django会生成一个CSRF令牌,并将其存储在服务器端的session中。当网站只用到cookie时,CSRF令牌值存在浏览器中csrftoken。

  2. 将CSRF令牌添加到表单:当使用{% csrf_token %}模板标签时,Django会将生成的CSRF令牌添加为一个隐藏的input字段,字段的名字通常是csrfmiddlewaretoken

  3. CSRF令牌验证:当用户提交包含CSRF令牌的表单时,Django会从表单中读取csrfmiddlewaretoken字段的值,并与服务器端会话中存储的CSRF令牌进行比较。如果两者匹配,请求会被视为合法的。如果令牌无效或者与会话不匹配,Django将拒绝请求,防止CSRF攻击。

  4. Cookie中的CSRF令牌:Django在生成CSRF令牌的同时,还会将这个令牌的值设置为一个cookie(通常名为csrftoken),以便在之后的请求中使用。这个cookie中的令牌值是通过浏览器的cookie机制来传递的。

综上所述,Django的CSRF保护机制在服务器端使用会话管理CSRF令牌,同时在客户端使用cookie来传递CSRF令牌的值。这种组合保证了请求的合法性,防止了CSRF攻击。

2、解决方案(依赖中间CsrfViewMiddleware)

第一种方案:在form表单中添加{% csrf_token %}

<form action="" method="post">
    {% csrf_token %}
    username:<input type="text">
    <input type="submit" value="提交">
</form>

第二种方案:没有form表单时,data中传 csrfmiddlewaretoken:'{% csrf_token %}'

<script>
    $(".btn").click(function() {
        $.ajax({
            url: '',
            type: 'POST',
            data:{'a':1, csrfmiddlewaretoken:'{% csrf_token %}'},
            success : function() {

            }
        })
    })
</script>


##########传文件时的情况,在myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}')写

$(".btn").click(function () {
        // 1 获取表单数据
        let username = $("#username").val();
        let password = $("#password").val();
        let re_password = $("#re_password").val();
        let email = $("#email").val();
        //  获取文件数据
        let my_file = $("#my_file")[0].files[0];

        // 2 参数验证
        let fields = [
            {id: 'username', msg: '用户名必须填写'},
            {id: 'password', msg: '密码必须填写'},
            {id: 're_password', msg: '确认密码必须填写'}
        ];
        for (let i = 0; i < fields.length; i++) {
            if (!$("#" + fields[i].id).val()) {
                layer.msg(fields[i].msg);
                return;
            }
        }

        var myFormDataObj = new FormData;
        myFormDataObj.append('username', username)
        myFormDataObj.append('password', password)
        myFormDataObj.append('re_password', re_password)
        myFormDataObj.append('email', email)
        myFormDataObj.append('my_file', my_file)
        myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}')

        // 3 发起ajax请求
        $.ajax({
            url: '',
            type: 'POST',
            data: myFormDataObj,
            contentType: false,
            processData: false,
            success: function (res) {
                if (res.code === 200) {
                    layer.msg(res.msg, {}, function () {
                        location.href = '/home/'
                    })
                }
            }
        })
    })

补充:当form表单和ajax同时存在时:不常用

<form action="" method="post">
    {% csrf_token %}
    username:<input type="text" name="username">
    <input type="submit" value="提交">
</form>
<script src="/static/my_csrf.js"></script>

<button class="btn btn-info">按钮</button>
<script>
    $(".btn").click(function() {
        $.ajax({
            url: '',
            type: 'POST',
            data:{"a":1, csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()},
            success : function() {

            }
        })
    })
</script>

$("[name='csrfmiddlewaretoken']").val()是name="username"标签下取掩藏key csrfmiddlewaretoken的值(浏览器可见)

第三种方案: 前后端项目分离

去官网复制js文件存在static下my_csrf.js中

Cross Site Request Forgery protection | Django documentation | Django (djangoproject.com)

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 = cookies[i].trim();
            // 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 protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

html中引入 <script src="/static/my_csrf.js"></script>

<script src="/static/my_csrf.js"></script>

<button class="btn btn-info">按钮</button>
<script>
    $(".btn").click(function() {
        $.ajax({
            url: '',
            type: 'POST',
            data:{'a':1, 'b':2 },
            success : function() {

            }
        })
    })
</script>

3、csrf 相关的装饰器

使用场景:对于特定需要保护的视图,可以使用@csrf_protect来确保它们不会受到CSRF攻击。

注销中间件,利用装饰器来做验证

# 'django.middleware.csrf.CsrfViewMiddleware',

views:导入模块 csrf_exempt, csrf_protect

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_protect  # 需要验证
def index(request):
    return render(request, 'csr.html')

@csrf_exempt # 不需要验证
def func(request):
    return render(request, 'csr.html')

  

 

posted @ 2023-08-11 15:32  凡人半睁眼  阅读(13)  评论(0编辑  收藏  举报