Backend - Django CSRF 跨域请求伪造

目录

[一、CSRF & XSS](#一、CSRF & XSS)

(一)CSRF

[1. 含义](#1. 含义)

[2. 攻击原理](#2. 攻击原理)

(1)浏览器特点

(2)攻击方式

(二)XSS

[1. 含义](#1. 含义)

[2. 攻击原理](#2. 攻击原理)

(三)二者区别

[二、Django Ajax CSRF 防御](#二、Django Ajax CSRF 防御)

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

[1. 原理](#1. 原理)

[2. 设置验证](#2. 设置验证)

[(二)双重cookie验证(Double Submit Cookie)](#(二)双重cookie验证(Double Submit Cookie))

[1. 原理](#1. 原理)

[2. 设置验证](#2. 设置验证)

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

[1. 原理](#1. 原理)

[2. 设置验证](#2. 设置验证)

[三、设定 CSRF 验证](#三、设定 CSRF 验证)

(一)settings.py

(二)base.html

[1. 针对 ajax 请求,body 里添加{% csrf_token %}](#1. 针对 ajax 请求,body 里添加{% csrf_token %})

[2. 针对 form 表单,form 表单里添加{% csrf_token %}](#2. 针对 form 表单,form 表单里添加{% csrf_token %})

(三)JS

[1. 针对 双重cookie验证](#1. 针对 双重cookie验证)

(1)方法1

(2)方法2

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

(1)方法1

[3. 针对所有模式的综合验证](#3. 针对所有模式的综合验证)

(1)写入位置

(2)引入顺序

[四、关闭 CSRF 防御功能](#四、关闭 CSRF 防御功能)

[1. 方法1:全局禁用](#1. 方法1:全局禁用)

[2. 方法2:局部禁用](#2. 方法2:局部禁用)

[五、Django CSRF 的控制台Error](#五、Django CSRF 的控制台Error)

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

[1. 原因](#1. 原因)

[2. 解决](#2. 解决)

[(二)CSRF verification failed. Request aborted.](#(二)CSRF verification failed. Request aborted.)

[1. 原因](#1. 原因)

[(1)原因1:csrf_token 过期](#(1)原因1:csrf_token 过期)

[(2)原因2:请求头的 csrf_token 与session存储的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 %}

例如:

html 复制代码
<body id="body">
    {% csrf_token %}
    <div>{% block content %} {% endblock %}</div>
</body>

渲染后:

html 复制代码
<body id="body">
    <input type="hidden" name="csrfmiddlewaretoken" value="vUAPUcghecxAGlraGaFGbikXz3SOPcWtmMtk8o1UQ1PpYYAhxg2cAiAaLyQ9HEY9" />
    <div>插入的子模板</div>
</body>

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

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

例如:

javascript 复制代码
<form action="http://127.0.0.1:8080/myApp/test" method=POST>
	{% csrf_token %}
	<input type="submit"/>
</form>

(三)JS

1. 针对 双重cookie验证

(1)方法1

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

在base.html中的script里写上。

javascript 复制代码
$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
(2)方法2

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

在base.html中的script里写上。

javascript 复制代码
$.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文件。

javascript 复制代码
$.ajaxSetup({
    headers:{ "X-CSRFtoken":$.cookie("csrftoken")},
});

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

(1)写入位置

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

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

(2)引入顺序

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

javascript 复制代码
/**
 * 【 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

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 %}

相关推荐
欧阳枫落6 分钟前
python 2小时学会八股文-数据结构
开发语言·数据结构·python
天天要nx10 分钟前
D64【python 接口自动化学习】- python基础之数据库
数据库·python
feifeikon1 小时前
Python Day5 进阶语法(列表表达式/三元/断言/with-as/异常捕获/字符串方法/lambda函数
开发语言·python
杰仔正在努力1 小时前
python成长技能之枚举类
开发语言·python
Eiceblue1 小时前
通过Python 调整Excel行高、列宽
开发语言·vscode·python·pycharm·excel
Jam-Young2 小时前
Python中的面向对象编程,类,对象,封装,继承,多态
开发语言·python
Light602 小时前
低代码牵手 AI 接口:开启智能化开发新征程
人工智能·python·深度学习·低代码·链表·线性回归
墨绿色的摆渡人2 小时前
用 Python 从零开始创建神经网络(六):优化(Optimization)介绍
人工智能·python·深度学习·神经网络
小han的日常2 小时前
pycharm分支提交操作
python·pycharm
明月清风徐徐3 小时前
Scrapy爬取豆瓣电影Top250排行榜
python·selenium·scrapy