Backend - Django CSRF 跨域请求伪造

目录

一、CSRF & XSS

(一)CSRF

1. 含义

2. 攻击原理

(1)浏览器特点

(2)攻击方式

(二)XSS

1. 含义

2. 攻击原理

(三)二者区别

二、Django Ajax CSRF 防御

(一)令牌同步模式(Synchronizer Token Pattern,简称STP)

1. 原理

2. 设置验证

(二)双重cookie验证(Double Submit Cookie)

1. 原理

2. 设置验证

(三)X-Csrf-Token验证(Cookie-to-header token)

1. 原理

2. 设置验证

三、设定 CSRF 验证

(一)settings.py

(二)base.html

1. 针对 ajax 请求,body 里添加{% csrf_token %}

2. 针对 form 表单,form 表单里添加{% csrf_token %}

(三)JS

1. 针对 双重cookie验证

(1)方法1

(2)方法2

2. 针对 X-Csrf-Token验证(Cookie-to-header token)

(1)方法1

3. 针对所有模式的综合验证

(1)写入位置

(2)引入顺序

四、关闭 CSRF 防御功能

1. 方法1:全局禁用

2. 方法2:局部禁用

五、Django CSRF 的控制台Error

(一)Reason given for failure: CSRF cookie not set.

1. 原因

2. 解决

(二)CSRF verification failed. Request aborted.

1. 原因

(1)原因1:csrf_token 过期

(2)原因2:请求头的 csrf_token 与session存储的token不匹配

(3)原因3:模板里没有csrfmiddlewaretoken


一、CSRF & XSS

(一)CSRF

1. 含义

        跨站请求伪造(Cross-site Request Forgery )。

2. 攻击原理

(1)浏览器特点

同个浏览器上,无论是目标网站A还是其他网站B,发送对目标网站A的HTTP请求,都会自动带上目标网站A的cookie,发送给服务端。

(2)攻击方式

同个浏览器上,当用户登录了目标网站(已登录状态),再进入攻击网站,攻击网站发送对目标网站的HTTP请求,则会自动带上“已登录的目标网站”的cookie,就可以进行攻击服务端。

(二)XSS

1. 含义

跨站脚本攻击(Cross-Site Scripting,为了和 CSS 区分,则简称 XSS)。

2. 攻击原理

在目标网站上注入恶意脚本进行攻击。(攻击者提交恶意代码,浏览器再执行恶意代码,篡改了网页)

(三)二者区别

CSRF 是 HTTP 问题,XSS 是代码注入问题。

CSRF需登录目标网站,XSS不用登录。

二、Django Ajax CSRF 防御

(一)令牌同步模式(Synchronizer Token Pattern,简称STP)

1. 原理

(1)找到数据库Session的session_csrftoken参数。成功登录网站后,后端随机产生一个csrftoken值,并把该值保存在数据库Session参数中。

(2)找到网页模板的隐藏csrfmiddlewaretoken名的标签。初始化某界面时,前端模板会根据{% csrf_token %}生成一个隐藏的name='csrfmiddlewaretoken'的input标签,存放后端随机生成的csrftoken值。

(3)用户进行 ajax post 请求。post请求时,csrfmiddlewaretoken值会一并放在请求数据(或头信息)中,发送给后端。后端会根据前端csrfmiddlewaretoken的 value值、和服务端数据库 public.django_session 表的 session_csrftoken参数值,判断两个csrf_token解密后的值是否一致。

(4)一致则正常访问,不一致则拒绝访问。

2. 设置验证

在第三点中。

(二)双重cookie验证(Double Submit Cookie)

1. 原理

(1)找到浏览器cookie的csrftoken。成功登录网站后,整个浏览器中Cookie的csrftoken属性,存放后端随机生成的csrftoken值。

(2)找到网页模板的隐藏csrfmiddlewaretoken名的标签。初始化某界面时,前端模板会根据{% csrf_token %}生成一个隐藏的 name='csrfmiddlewaretoken' 的input标签,存放后端随机生成的csrftoken值。

(3)用户进行 ajax post 请求。post请求时,csrfmiddlewaretoken值会一并放在请求数据(或头信息)中,发送给后端。后端会根据前端csrfmiddlewaretoken的 value值、和浏览器Cookie的csrftoken值,判断两个csrf_token解密后的值是否一致。

(4)一致则正常访问,不一致则拒绝访问。

2. 设置验证

在第三点中。

(三)X-Csrf-Token验证(Cookie-to-header token)

1. 原理

(1)确保同源政策。

(2)系统主要使用JavaScript进行交互。(因为恶意攻击无法读取cookie值并复制到HTTP请求头中)

(3)将cookie上的token复制到HTTP请求头中。

(4)后端验证HTTP请求头中token的存在和完整性。

(5)X-Csrf-Token头存在且完整,则正常访问,否则拒绝访问。

2. 设置验证

在第三点中。

三、设定 CSRF 验证

以下主要针对基于 django 使用 ajax 发送 post 请求时的验证。

(一)settings.py

        MIDDLEWARE里添加'django.middleware.csrf.CsrfViewMiddleware'  # 设置CSRF检测功能

(二)base.html

1. 针对 ajax 请求,body 里添加{% csrf_token %}

例如:


    {% csrf_token %}
    
{% block content %} {% endblock %}

渲染后:


    
    
插入的子模板

2. 针对 form 表单,form 表单里添加{% csrf_token %}

因为若在 base.html 中加入 {% csrf_token %},是不在 form 表单的范围内。所以需要在 form 表单里添加。

例如:

{% csrf_token %}

(三)JS

1. 针对 双重cookie验证

(1)方法1

        后端将csrftoken传到前端(放置在隐藏标签里),发送post请求时,请求数据data中加上csrftoken,一起发送给后端。

        在base.html中的script里写上。

$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
(2)方法2

        后端将csrftoken传到前端(放置在隐藏标签里),发送post请求时,请求数据data中加上csrftoken。

        在base.html中的script里写上。

$.ajaxSetup({
    data: {csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()},
});

2. 针对 X-Csrf-Token验证(Cookie-to-header token)

(1)方法1

        cookie中存在csrftoken,请求头headers中加上csrftoken。

        在base.html中的script里写上。

        前提:

                ① 引入jquery-3.1.1.min.js和jquery.cookie.js

                ② 引入顺序:jQuery库文件必须先于cookie文件。

$.ajaxSetup({
    headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
});

3. 针对所有模式的综合验证

(1)写入位置

        前面两个验证的所有方法只能写在html中,不能写到外部js文件。因为{{ csrf_token }} 渲染在模板上,若以外部文件引入,则不能执行。

        以下代码可以写在外部js文件里,并在 base.html 里引入该js文件。

(2)引入顺序

        该 js 文件的引入顺序必须在 jquery.js 文件之后。

/**
 * 【 Cross Site Request Forgery TOKEN 】
 *  Forbidden 403 - CSRF check with an AJAX POST request in Django.
 */
jQuery(document).ajaxSend(function (event, xhr, settings) {
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            let cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                let 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;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        let host = document.location.host; // host + port
        let protocol = document.location.protocol;
        let sr_origin = '//' + host;
        let origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url === origin || url.slice(0, origin.length + 1) === origin + '/') ||
            (url === sr_origin || url.slice(0, sr_origin.length + 1) === sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

四、关闭 CSRF 防御功能

不推荐关闭 CSRF 防御功能,因为取消了 CSRF 防御保护。

1. 方法1:全局禁用

        settings.py中,注释掉'django.middleware.csrf.CsrfViewMiddleware'

2. 方法2:局部禁用

        views.py中,导入from django.views.decorators.csrf import csrf_exempt;

        并给要处理post数据的函数补充@csrf_exempt(post函数有request参数)。

五、Django CSRF 的控制台 Error

(一)Reason given for failure: CSRF cookie not set.

1. 原因

        django 中使用 jquery ajax post 数据出现 403 错误。

        即,settings设置了Django CSRF检测功能(防止跨站请求伪造),需要在django发送post请求时进行字符串验证,但还没有设置CSRF cookie。

2. 解决

(1)第一种:关闭 CSRF 检测功能

(2)第二种:设定 CSRF 验证

(这两种方式在前面第三点中已介绍)

(二)CSRF verification failed. Request aborted.

1. 原因

(1)原因1:csrf_token 过期

        解决:重新登录(若还未写前端登录,则admin登录)

(2)原因2:请求头的 csrf_token 与session存储的token不匹配

        解决:清除浏览器缓存; 重新登录

(3)原因3:模板里没有csrfmiddlewaretoken

        解决:模板中(或表单内)添加 {% csrf_token %} 

你可能感兴趣的:(csrf,Django,python,token)