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>
相关文章
相关标签/搜索