django——csrf跨站

django——csrf跨站

目录

  • csrf跨站请求伪造
  • django完成csrf校验
  • csrf相关装饰器

csrf跨站请求伪造

简介

CSRF就是跨站请求(HTTP请求)伪造,是一种对网站的恶意利用。

就是用户通过伪造的网页向服务器发送请求,而伪造的网页用户所输入的信息是被篡改后才向服务器发送请求,从而达到跨站请求伪造

如何预防跨站请求伪造

通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求。当这个页面向后端发送post请求后,后端会先校验唯一标识,如果标识不对直接拒绝(403 forbidden),如果校验成功就继续执行。

django完成csrf校验

django的csrf跨站请求伪造校验由csrf中间件完成

该中间件为:
'django.middleware.csrf.CsrfViewMiddleware'

form表单校验

创建from表单后,提交from表单,会返回403 forbidden,是因为没有进行csrf验证

  • 如何对csrf验证

    在form表单中进行csrf验证只需在form表单中加入{% csrf_token %}即可

    <form action="" method="post">
        {% csrf_token %}
        <p>username:<input type="text"></p>
        <p>password:<input type="text"></p>
        <p><input type="submit" class="btn btn-primary"></p>
    </form>
    

    此时就能向后端发送post请求,并且页面中多出了csrfmiddlewaretoken,这就是后端给浏览器的唯一标识,每次访问都会改变。

ajax进行校验

  • 创建ajax请求

    <p>
        <button class="btn btn-danger" id="btn">点这里发送ajax请求</button>
    </p>
    <script>
        $('#btn').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'user':'wjl', 'pswd':'123'},
                success: function () {
                    alert('发送成功')
                }
            })
        })
    </script>
    
    

    此时由于没有进行csrf验证,访问结果仍为403

  • ajax有三种方法可以对csrf进行验证

    ①利用标签获取页面上的csrfmiddlewaretoken,添加到data中

    在所创建的Ajax中的data数据添加csrfmiddlewaretoken数据值
    data: {'user':'wjl', 'pswd':'123','csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken].val()')},
        获取此时访问的csrf的密文
    

    ②使用模板语法提供的快捷方式{{ csrf_token }}

    在所创建的Ajax中的data数据添加csrfmiddlewaretoken数据值
     data: {'user':'wjl', 'pswd':'123', 'csrfmiddlewaretoken':'{{ csrf_token }}' },
    

    ③使用js脚本(通用方式)

    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);
            }
        }
    });
    
    

    创建好js代码之后,将此js脚本引入到ajax中即可

    {% load static %}
        <script src="{% static 'js/mycsrf.js' %}"></script>    
    <script>
        $('#btn').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'user':'wcy', 'pswd':'123'},
                success: function () {
                    alert('发送成功')
                }
            })
        })
    </script>
    
    

以上三种方式都能成功完成ajax请求的csrf校验,第三种方式最常用

csrf 装饰器

csrf相关的装饰器

csrf相关的装饰器主要使用以下两个

from django.views.decorators.csrf import csrf_exempt, csrf_protect
"""
csrf_exempt        不需要校验
csrf_protect       需要校验
"""
  • 其使用场景有两个

    ①网站整体不需要csrf校验,但一部分需要校验

    ②网站整体都需要csrf校验,但一部分不需要校验

FBV

①网站整体不需要csrf校验,但一部分需要校验

首先要先在配置文件中注释掉csrf中间件,在login函数上使用csrf_protect装饰器, 此时login需要验证

@csrf_protect
def login(request):
    return render(request, 'login.html')

前端

<form action="" method="post">
 	{% csrf_token %}
    <p>username:<input type="text"></p>
    <p>password:<input type="text"></p>
    <p><input type="submit" class="btn btn-primary"></p>
</form>

此时如果注释掉form表单中的{% csrf_token %}将会返回403forbidden错误,添加校验才会继续执行

②网站整体都需要csrf校验,但一部分不需要校验

在login出使用csrf_exempt装饰器

@csrf_exempt
def login(request):
    return render(request, 'login.html')

前端

<form action="" method="post">
{#    {% csrf_token %}#}
    <p>username:<input type="text"></p>
    <p>password:<input type="text"></p>
    <p><input type="submit" class="btn btn-primary"></p>
</form>

此时依然能够提交post请求,说明此时login不需要验证

CBV

针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法

首先需要先编写CBV

from django.views import View

class MyView(View):
    def get(self, request):
        return HttpResponse('get方法')

    def post(self, request):
        return HttpResponse('post方法')

CBV添加装饰器的方式有三种,在不同场景下三种方法的用法

场景①网站整体不需要csrf校验,但一部分需要校验

1.直名道姓的在类中的方法上添加

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


class MyView(View):
    def get(self, request):
        return HttpResponse('get方法')

    @method_decorator(csrf_protect)
    def post(self, request):
        return HttpResponse('post方法')

2.指名道姓的在类名上添加

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


@method_decorator(csrf_protect, name='post')
class MyView(View):
    def get(self, request):
        return HttpResponse('get方法')

    # @method_decorator(csrf_protect)
    def post(self, request):
        return HttpResponse('post方法')

3.影响类中所有的方法

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


class MyView(View):

    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super(MyView, self).dispatch(request, *args, **kwargs)
    
    def get(self, request):
        return HttpResponse('get方法')

    def post(self, request):
        return HttpResponse('post方法')

场景②的使用CBV的方法与场景①一致,将装饰器 @method_decorator(csrf_protect)换为@method_decorator(csrf_exempt)即可

posted @ 2022-09-13 17:06  Nirvana*  阅读(66)  评论(0)    收藏  举报