django csrf 验证问题及 csrf 原理

2023-02-18 11:48:26 浏览数 (1)

相关文档

  • 跨站请求伪造保护 (1.8 官方文档翻译)
  • Cross Site Request Forgery protection (2.2 官方文档)
  • django csrf 验证问题及 csrf 原理
  • django 前后端分离 csrf 验证的解决方法
  • django 进阶 ( csrf、ajax )

模板获取 csrf_token 

代码语言:javascript复制
{{ csrf_token }}  # 在html这样写,前端就会显示它
{% csrf_token %}  # 在html这样写,不会显示,但是会生成一个隐藏的input框,type=hidden

django 模板里 ajax 请求携带 csrf_token 常用做法

注意:此做法 ajax 要写在 django 模板里,写在 .js 里无效。

代码语言:javascript复制
<script>
    // 要直接写在 HTML 文件里,才能用 {{ csrf_token }} 直接获取 csrf_token
    var cur_url = window.location.href;

    function visit_web() {
        var url = "/index/";
        $.ajax({
            url: url,
            data: {
                cur_url: cur_url,
                // 传值 csrf 
                csrfmiddlewaretoken: '{{ csrf_token }}'
            },
            type: "post",
            dataType: "json",
            success: function (responese) {
                if (responese.status === 201) {
                    console.log("访问成功");
                }
            },
            error: function (responese) {
                console.log("访问失败");
            }
        });
    }

    window.onload = visit_web; // 网页加载完成后运行
</script>

ajax 请求携带 csrf_token 常用做法

1. 直接请求接口,拿到 csrf_token,设置路由为 /get_csrf_token

代码语言:javascript复制
from django.middleware.csrf import get_token


def get_csrf_token(request):
    return JsonResponse({'token': get_token(request)})

2. 然后既可以添加到请求头,也可以直接添加到 请求 data 的 csrfmiddlewaretoken 或 X-CSRFToken

直接给该页面所有 ajax 请求设置请求头

代码语言:javascript复制
<script>
    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    function set_ajax_csrf_token() {
        var url = "/get_csrf_token";
        $.ajax({
            url: url,
            data: {},
            type: "get",
            dataType: "json",
            success: function (responese) {
                storage.csrf_token = responese.token;
                // 给 ajax 请求设置请求头 x-csrftoken
                $.ajaxSetup({
                    beforeSend: function (xhr, settings) {
                        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                            xhr.setRequestHeader("X-CSRFToken", responese.token);
                        }
                    }
                });
            },
            error: function (responese) {
                console.log("get csrf failed!");
            }
        });

    }
   
     // 运行多个函数
    $(window).load(function () {
        set_ajax_csrf_token();
    });

</script>

拿到 csrf_token 后存起来,需要的请求添加 csrf_token(localStorage 使用总结)

代码语言:javascript复制
<script>
    // 定义全局变量
    var storage = window.localStorage;
    
    // 请求接口方式 获取 csrf_toke,该方法可用于 .js 文件中,可完全前后端分离
    function get_token() {
        var url = "/get_csrf_token";
        $.ajax({
            url: url,
            data: {},
            type: "get",
            dataType: "json",
            success: function (responese) {
                // 保存 csrf_toke
                storage.csrf_token = responese.token;
            },
            error: function (responese) {
                console.log("get csrf failed!");
            }
        });

    }
    
    // 官方做法 获取 csrf_toke,该方法可用于 .js 文件中,前端必须是 django 模板渲染
    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');
    
    
    // POST 请求
    function post_token() {
        var url = "/blog/test_csrf";
        $.ajax({
            url: url,
            data: {
                token: 1232312
            },
            type: "post",
            dataType: "json",
            // 单独给 post 请求设置 X-CSRFToken
            beforeSend: function (xhr) {
                xhr.setRequestHeader("X-CSRFToken", storage.csrf_token);
            },
            success: function (responese) {
                console.log("csrf test")
            },
            error: function (responese) {
                console.log("csrf error");
            }
        });
    }


    // 运行多个函数
    $(window).load(function () {
        get_token();
    });
    
    // 查看 csrf_token
    console.log(storage.csrf_token);
</script>

对单个视图忽略 csrf 验证

代码语言:javascript复制
from django.views.decorators.csrf import csrf_exempt


# 给需要忽略的视图加 装饰器 csrf_exempt
@csrf_exempt
def test(request):
    # ...
    returen HttpResponse("Hello World")

注释掉 CsrfViewMiddleware 中间件 (不推荐)

注释掉 settings.py 里面的  'django.middleware.csrf.CsrfViewMiddleware' 后,所有 post请求就不会验证码 csrf_token 了,有一定安全风险。

代码语言:javascript复制
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 注释掉 csrf 验证
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

0 人点赞