django-csrf跨站请求伪造

django-csrf跨站请求伪造

一、什么是跨站请求伪造

  跨站请求伪造。英文简称:csrf,英文全称:cross-site request forgery

  举个栗子:钓鱼网站

    有一个和某银行一摸一样的虚假网站,用户在该页面完成转账功能,转账的请求是朝着银行的真实网站的服务端提交,这两个网站提交数据的唯一不同在于收款账户人不同,在虚假网站书写收款人的form表单,此页面的input输入框没有name属性,虚假网站开发人员提前写好一个具有默认的并且是隐藏的具有name属性的input,所以向银行真实服务端提交数据的时候,默认就是将你的金额转给了默认写好的账户,这种虚假网站就叫做钓鱼网站,这种方式叫做跨站请求伪造。

  那么如何开启csrf校验,防止此类事情出现呢?

 

 

二、django如何开启csrf校验

  csrf是django的默认中间件,默认是开启的,对前端请求进行校验;将其注释即关闭校验。

  但是在开启情况下,前端向后台提交数据会被阻拦报出 403 forbidden 错误。那么如何通过这种校验呢?

  PS:关闭csrf中间件即可通过校验,但是出于数据安全考虑,不建议此类操作,可做简单测试使用,不推荐使用于生产环境。下文不对此方法进行叙述。

 

 

三、如何正确通过csrf校验

1、前端的form表单如何通过csrf校验

  在form表单内书写一个{% csrf_token %}即可,例:

  这样的话,后端会返回给前端一串随机字符串,前端向后端再次发送数据时,后端的csrf中间件会对这一串字符串进行校验,校验成功正确即返回数据,校验不成功即 403 forbidden 报错。

 

2、ajax如何通过csrf校验

  第一种:手动获取

$.ajax({
    url: '',
    type: 'post',
    // 第一种方式:手动获取
    data:{'username':'tom', 'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()}
    success:function (data) {
        alert(data)
    }
})

  第二种:利用模板语法

$.ajax({
    url: '',
    type: 'post',
    // 第二种方式:使用模板语法
    data:{'username':'tom', 'csrfmiddlewaretoken':'{{ csrf_token }}'}
    success:function (data) {
        alert(data)
    }
})

  第三种:通用方式,引入外部js文件

    ① cv大法,创建myset.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 = 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 protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});
自定义myset.js文件

    ② 在html中引入文件

// 加载静态文件
{% load static %}
// 引入自定义myset.js文件
<script src="{% static 'myset.js' %}"></script>

    ③ ajax按照语法正常写即可

$.ajax({
    url: '',
    type: 'post',
    // 第三种方式:通用方式,引入外部js文件
    data:{'username':'tom'}
    success:function (data) {
        alert(data)
    }
})

 

 

四、csrf相关装饰器

1、当网站整体都使用csrf校验的时候,我想让某几个视图函数不使用csrf校验(配置文件中中间件配置csrf没有被注释,默认全部校验)

(1)FBV:基于函数的视图

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


@csrf_exempt  # 整体都校验,该视图函数不校验csrf
def login(request):
    return render(request, 'login.html')

(2)CBV:基于类的视图

  csrf_exempt的两种方式:

# csrf_exempt的两种方式:
from django.views import View
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


# @method_decorator(csrf_protect, name='dispatch')  # 第二种方式:一定要指定dispatch方法,所以第二种方法==第一种方法
class MyHome(View):

    @method_decorator(csrf_exempt)  # 第一种方式:给类中所有的方法都加上装饰器
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, 'get_demo.html')

    def post(self, request):
        return HttpResponse('请求完成')

 

2、当网站整体都不使用csrf校验的时候,我想让某几个视图函数使用csrf校验(配置文件中中间件配置csrf被注释,默认全部不校验)

(1)FBV:基于函数的视图

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


@csrf_protect  # 整体都不校验,该视图函数校验csrf
def login(request):
    return render(request, 'login.html')

(2)CBV:基于类的视图

  csrf_protect的三种方式:

# csrf_protect的三种方式:
from django.views import View
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


@method_decorator(csrf_protect, name='post')  # 第二种方式:指名道姓的给某个方法装饰
class MyHome(View):

    # @method_decorator(csrf_protect)  # 第三种方式:给类中所有的方法都加上装饰器
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, 'get_demo.html')

    # @method_decorator(csrf_protect)  # 第一种方式:直接在方法上面装饰
    def post(self, request):

 

3、总结

  ① 给CBV加装饰器,推荐使用method_decorator模块

  ② 自定义的装饰器和csrf_protect的用法一致

  ③ 唯独scrf_exempt是一个特例,只能给dispatch方法装饰

posted @ 2020-12-15 22:41  chchcharlie、  阅读(216)  评论(0编辑  收藏  举报