zoukankan      html  css  js  c++  java
  • Django 2.0 学习(22):Django CSRF

    Django 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攻击的方式有两种:

    • 在表单中附加csrftoken;
    • 通过request请求中添加x-csrftoken请求头;

    注意:Django默认对所有的POST请求都进行csrftoken验证,若验证失败则返回403错误。Django中设置防跨站请求伪造功能分为全局和局部。
    全局:中间件 django.middleware.csrf.CsrfViewMiddleware
    局部:from django.views.decorators.csrf import csrf_protect, csrf_exempt

    • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件;
    • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件;

    当用post提交数据的时候,django会去检查是否有一个csrf的随机字符串,如果没有就会报错,错误如下:

    在Django内部支持生成这个随机字符串。

    通过form提交
    在form表单里面需要添加{% csrf_token %},这样当查看页面源码的时候,可以看到form中有一个input是隐藏的:

    原理总结:
    当用户访问login页面的时候,会生成已给csrf的随机字符串,并且cookie中野村放了这个随机字符串,当用户再次提交数据的时候会带着这个随机字符串提交,如果没有这个随机字符串则无法提交成功。cookie中存放的csrftoken如下图所示:

    通过ajax提交
    因为cookie中同样存在csrftoken,所以可以在JavaScript中通过$.cookie("csrftoken")获取。如果通过ajax进行提交数据,这里提交的csrftoken是通过请求头中存放,需要提交一个字典型的数据,即这时候需要一个key。在views中的login函数中:from django.conf import settings,然后打印print(settings.CSRF_HEADER_NAME),这里需要注意一个问题,这里导入的settings并不是我们在项目下看到的settings.py文件,这里是一个全局的settings配置,而当我们在项目目录下的settings.py中配置的时候,我们添加的配置则会覆盖全局settings中的配置。print(settings.CSRF_HEADER_NAME)打印的内容为:HTTP_X_CSRFTOKEN,这里的HTTP_X_CSRFTOEKN是Django在X_CSRF的前面添加了HTTP_,所以实际传递的就是X_CSRFTOKEN,而在前端页面的ajax传递的时候由于不能使用下划线,所以传递的是X_CSRFTOKEN。下面是在前端ajax中写的具体内容:

    $("#btn1").click(function () {
            $.ajax({
                url:"/login/",
                type:"POST",
                data:{"usr":"root","pwd":"123"},
                headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
                success:function (arg) {
    
                };
            });
        });
    

    但是如果页面中有多个ajax请求的话,就在每个ajax中添加headers信息,所以可以通过下面方式在所有的ajax中都添加:

     $.ajaxSetup({
                beforeSend:function (xhr,settings) {
                    xhr.setRequestHeader("X-CSRFtoken",$.cookie("csrftoken"))
                }
            });
    

    这样就会在提交ajax之前执行这个方法,从而在所有的ajax里都加上这个csrftoken,这里的xhr是XMLHttpRequest的简写,ajax调用的就是这个方法。如果想要实现在当get方式的时候不需要提交csrftoken,当post的时候需要,实现这种效果的代码如下:

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

    这样就实现了当GET|HEAD|OPTIONS|TRACE这些方式请求的时候不需要提交csrftoken。

    总结:
    1、csrf在ajax提交的时候通过请求头传递给后台的;
    2、csrf在前端的key为:X-CSRFToken,到后端的时候Django会自动添加HTTP_,并且最后为HTTP_X_CSRFTOKEN;
    3、csrf在form中提交的时候需要在前端form中添加{% csrftoken %};

  • 相关阅读:
    maven_Error building POM (may not be this project's POM)错误
    jmeter经验---java 追加写入代码一例
    java I/O Stream 代码学习总结
    java 布尔值一种赋值方法
    Spring cloud config 使用gitHub或者gitee连接
    linux/mac下一键删除下载失败的maven jar包
    MYSQL主从复制制作配置方案
    centos7 下解决mysql-server找不到安装包问题
    基于存储过程的百万级测试数据自动生成
    mysql慢查询,死锁解决方案
  • 原文地址:https://www.cnblogs.com/love9527/p/9254149.html
Copyright © 2011-2022 走看看