Django: csrf防御机制

作者: Ljian1992 | 来源:发表于2015-10-05 22:17 被阅读8502次

    csrf攻击过程

    csrf攻击说明csrf攻击说明

    1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

    2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

    3.用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

    4.网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

    5.浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

    csrf的攻击之所以会成功是因为服务器端身份验证机制可以通过Cookie保证一个请求是来自于某个用户的浏览器,但无法保证该请求是用户允许的。因此,预防csrf攻击简单可行的方法就是在客户端网页上添加随机数,在服务器端进行随机数验证,以确保该请求是用户允许的。Django也是通过这个方法来防御csrf攻击的。

    在django防御csrf攻击

    原理

    在客户端页面上添加csrftoken, 服务器端进行验证,服务器端验证的工作通过'django.middleware.csrf.CsrfViewMiddleware'这个中间层来完成。在django当中防御csrf攻击的方式有两种, 1.在表单当中附加csrftoken 2.通过request请求中添加X-CSRFToken请求头。注意:Django默认对所有的POST请求都进行csrftoken验证,若验证失败则403错误侍候。

    在表单中附加csrftoken

    后端

    from django.shortcuts import render
    from django.template.context_processors import csrf
    
    def ajax_demo(request):
         # csrf(request)构造出{‘csrf_token’: token}
        return render(request, 'post_demo.html', csrf(request))
    

    前端

      $('#send').click(function(){
                    
        $.ajax({
            type: 'POST',
            url:'{% url 'ajax:post_data' %}',
            data: {
                    username: $('#username').val(),
                    content: $('#content').val(),
                   'csrfmiddlewaretoken': '{{ csrf_token }}'  关键点
                },
            dataType: 'json',
            success: function(data){
    
            },
            error: function(){
        
            }
        
        });
      });
    

    通过request请求中添加X-CSRFToken请求头

    后端

    该方式需要借助于Cookie传递csrftoken, 设置Cookie的方式有两种。ps:经测试即便什么都不做,也会设置Cookie,不过官方文档说,不保证每次都有效

    1.表单中添加{%csrf_token%}这个模板标签

    <form id="comment_form" action="#"></form>
    {% csrf_token %}   就是这个
    <p>姓名: <input type="text" name="useranme" id="username"></p>
    <p>内容: <textarea name="content" id="content" rows="5" cols="30"></textarea></p>
    <p><input type="button", id="send" value="提交"></p> 
    

    2.ensure_csrf_cookie装饰器。

    from django.shortcuts import render
    from django.views.decorators.csrf import ensure_csrf_cookie
    
    @ensure_csrf_cookie
    def ajax_demo(request):
        return render(request, 'ajax_demo.html')
    

    前端
    前端要做的事情,在进行post提交时,获取Cookie当中的csrftoken并在请求中添加X-CSRFToken请求头, 该请求头的数据就是csrftoken。通过$.ajaxSetup方法设置AJAX请求的默认参数选项, 在每次ajax的POST请求时,添加X-CSRFToken请求头

    <script type="text/javascript">
        $(function(){
    
            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;
            }
    
            <!--获取csrftoken-->
            var csrftoken = getCookie('csrftoken');
            console.log(csrftoken);
    
            //Ajax call
            function csrfSafeMethod(method) {
                // these HTTP methods do not require CSRF protection
                return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
            }
    
            $.ajaxSetup({
                crossDomain: false, // obviates need for sameOrigin test
                //请求前触发
                beforeSend: function(xhr, settings) {
                    if (!csrfSafeMethod(settings.type)) {
                        xhr.setRequestHeader("X-CSRFToken", csrftoken);
                    }
                }
            });
    
            $('#send').click(function(){
                console.log($("#comment_form").serialize());
    
                $.ajax({
                    type: 'POST',
                    url:'{% url 'ajax:post_data' %}',
                    data: {
                            username: $('#username').val(),
                            content: $('#content').val(),
                           //'csrfmiddlewaretoken': '{{ csrf_token }}'
                        },
                    dataType: 'json',
                    success: function(data){
                             
                        
                    },
                    error: function(){
    
                    }
    
                });
            });
    
    
        });
    </script>
    

    取消csrftoken验证

    通过csrf_exempt, 来取消csrftoken验证,方式有两种。
    1 .在视图函数当中添加csrf_exempt装饰器

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def post_data(request):
        pass
    

    2 .在urlconf当中

    from django.views.decorators.csrf import csrf_exempt
    urlpatterns = [
        url(r'^post/get_data/$', csrf_exempt(post_data), name='post_data'),
    
    ]
    
    

    参考:

    django官网文档

    相关文章

      网友评论

      • LucasJin:大佬,django后台自动验证csrf很强大,但是问题来了,我在安卓端或者iOS端怎么生成一个csrf token并添加到了header里面去呢?
      • lambdang:csrf验证就两个途径一个是给ajax请求数据每次加个验证信心 一个是通过cookie把验证信息加在请求头上 这两个方法还是第一个好 通过cookie问题多不说还要每次都设置装饰器
      • lambdang:ensure_csrf_cookie装饰器例子错了 不能加在ajax请求的函数上 因为ajax请求的时候jq已经把scrftonken写在这个请求头上了 而你在这个请求后在设置csrftonken 很明显 ajax请求头的csrf是空的

      本文标题:Django: csrf防御机制

      本文链接:https://www.haomeiwen.com/subject/klggcttx.html