django下防御race condition漏洞(竞争型漏洞)

news/2025/3/12 15:46:10/

目录

竞争型漏洞

概念

常见类型及示例

环境搭建

​编辑漏洞复现

ucenter/1/

ucenter/2/

ucenter/3/

ucenter/4/

总结

悲观锁

乐观锁


竞争型漏洞

概念

竞争型漏洞,也称为竞态条件漏洞(Race Condition Vulnerability),是由于程序在处理共享资源时,未能正确同步多个并发操作,导致执行结果依赖于这些操作的时序,从而可能被攻击者利用的安全漏洞。

假设有一个银行应用,处理转账的时候,如果两个转账操作同时进行,而余额检查没有正确同步,可能导致余额错误地被处理。例如,用户A有100元,同时发起两笔转账,各转出100元,如果系统没有正确锁定资源,可能两笔转账都通过,导致用户A的余额变成负数,这就是竞争条件导致的漏洞。

常见类型及示例

  1. TOCTOU(Time-of-Check to Time-of-Use)

    • 原理:程序在检查资源状态后、使用资源前,攻击者篡改资源。

    • 示例:检查文件权限后,攻击者替换为恶意文件,导致高权限执行。

    • 场景:文件系统操作、权限验证。

  2. 资源争用

    • 原理:并发操作修改同一资源(如余额、库存)时未同步。

    • 示例:电商系统中,两用户同时购买最后一件商品,导致超卖。

    • 场景:金融交易、库存管理。

  3. 异步操作漏洞

    • 原理:回调或事件处理顺序不当引发状态混乱。

    • 示例:JavaScript中多个异步回调修改同一变量,导致数据错误。

    • 场景:前端应用、分布式任务处理。

下面介绍一个关于竞争性的漏洞

环境搭建

可以在资源中下载文件解压

将文件上传到linux下,我们修改文件按中的错误,

将.env.defaul修改为.env

修改文件中的DEBUG=True

然后进行如下操作

pip3 install -r requirements.txt python3 manage.py migratepython3 manage.py collectstaticpython3 manage.py createsuperuserpython3 manage.py runserver  0.0.0.0:8080

完成之后可以访问网站

漏洞复现

ucenter/1/

无锁无事务时的竞争攻击

class WithdrawView1(BaseWithdrawView):success_url = reverse_lazy('ucenter:withdraw1')def form_valid(self, form):amount = form.cleaned_data['amount']self.request.user.money -= amountself.request.user.save()models.WithdrawLog.objects.create(user=self.request.user, amount=amount)return redirect(self.get_success_url())

利用bp抓包,当出现两次以上的扣款成功,就说明漏洞利用成功

竞争成功

查看日志 

ucenter/2/

无锁有事务时的竞争攻击

class WithdrawView2(BaseWithdrawView):success_url = reverse_lazy('ucenter:withdraw2')@transaction.atomicdef form_valid(self, form):amount = form.cleaned_data['amount']self.request.user.money -= amountself.request.user.save()models.WithdrawLog.objects.create(user=self.request.user, amount=amount)return redirect(self.get_success_url())

继续竞争

 查看日志

竞争成功。

ucenter/3/

悲观锁加事务防御Race Condition

class WithdrawView3(BaseWithdrawView):success_url = reverse_lazy('ucenter:withdraw3')def get_form_kwargs(self):kwargs = super().get_form_kwargs()kwargs['user'] = self.userreturn kwargs@transaction.atomicdef dispatch(self, request, *args, **kwargs):self.user = get_object_or_404(models.User.objects.select_for_update().all(), pk=self.request.user.pk)return super().dispatch(request, *args, **kwargs)def form_valid(self, form):amount = form.cleaned_data['amount']self.user.money -= amountself.user.save()models.WithdrawLog.objects.create(user=self.user, amount=amount)return redirect(self.get_success_url())

 发现只有一次提款成功

ucenter/4/

乐观锁加事务防御Race Condition

class WithdrawView4(BaseWithdrawView):success_url = reverse_lazy('ucenter:withdraw4')@transaction.atomicdef form_valid(self, form):amount = form.cleaned_data['amount']rows = models.User.objects.filter(pk=self.request.user, money__gte=amount).update(money=F('money')-amount)if rows > 0:models.WithdrawLog.objects.create(user=self.request.user, amount=amount)return redirect(self.get_success_url())

发现也只有一次成功

总结

悲观锁

概念

  • 悲观锁假设并发冲突一定会发生,因此在访问数据时直接加锁,确保其他事务无法修改数据,直到当前事务完成。

  • 悲观锁通常通过数据库的锁机制实现,如 SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE

特点

  • 优点:保证数据的一致性,适合写操作多的场景。

  • 缺点:加锁会降低并发性能,可能导致死锁。

使用场景

  • 高并发写操作。

  • 数据一致性要求高的场景。

实例

该例子需要实现一个转账操作,确保余额不会出现负数。

SELECT ... FOR UPDATE 中,账户A的记录被锁定,其他事务无法修改,直到当前事务提交或回滚。

-- 开启事务
START TRANSACTION;-- 使用悲观锁锁定账户A的记录
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;-- 检查余额是否足够
IF (SELECT balance FROM accounts WHERE id = 1) >= 100 THEN-- 扣除账户A的余额UPDATE accounts SET balance = balance - 100 WHERE id = 1;-- 增加账户B的余额UPDATE accounts SET balance = balance + 100 WHERE id = 2;
END IF;-- 提交事务
COMMIT;

乐观锁

概念

  • 乐观锁假设并发冲突很少发生,因此在访问数据时不加锁,而是在提交时检查数据是否被其他事务修改过。

  • 乐观锁通常通过版本号(Version)或时间戳(Timestamp)实现。

特点

  • 优点:提高并发性能,适合读操作多的场景。

  • 缺点:如果冲突频繁,会导致大量事务回滚。

使用场景

  • 高并发读操作。

  • 冲突较少的场景。

实例

在乐观锁中,通过 version 字段检查数据是否被修改。如果 version 不匹配,说明数据已被其他事务修改,当前事务需要回滚并重试。

即,当用户A进行提款操作时,若存在两个以上的请求进程(查询的version为1),当某一个进程率先请求成功,version会自增1,其他的进程就无法查询到该版本号,从而不会执行账户操作,事务回滚。

-- 开启事务
START TRANSACTION;-- 查询账户A的余额和版本号
SELECT balance, version FROM accounts WHERE id = 1;-- 假设查询到的 balance = 500, version = 1
-- 检查余额是否足够
IF 500 >= 100 THEN-- 扣除账户A的余额,并更新版本号UPDATE accounts SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 1;-- 检查是否更新成功IF ROW_COUNT() = 0 THEN-- 版本号不匹配,说明数据已被其他事务修改,回滚事务ROLLBACK;ELSE-- 增加账户B的余额UPDATE accounts SET balance = balance + 100 WHERE id = 2;-- 提交事务COMMIT;END IF;
END IF;


http://www.ppmy.cn/news/1578342.html

相关文章

vue3中接收props的两种写法

在 Vue 3 中,接收 props 有两种主要的写法,分别是运行时声明和基于类型的声明。下面为你详细介绍这两种写法。 1. 运行时声明 运行时声明是 Vue 2 中就已经存在的方式,在 Vue 3 中依然可以使用。这种方式通过在组件中使用 defineProps 宏来…

VSCode离线安装Verilog插件教程

本章教程,主要介绍如何在vscode中离线安装Verilog插件。 插件名称:Verilog-HDL/SystemVerilog/Bluespec SystemVerilog 一、下载插件 下载地址:https://open-vsx.org/extension/mshr-h/veriloghdl 二、离线安装 vscode离线安装步骤如下&#…

电力行业中分布式能源管理(Distributed Energy Management System, DEMS)的实现

以下是电力行业中分布式能源管理(Distributed Energy Management System, DEMS)的实现方案,涵盖系统架构、关键技术、核心功能及实施路径,结合典型场景与代码示例: 一、系统架构设计 采用云-边-端三层架构,实现分布式能源的高效协同管理: 1. 终端层(感知层) 设备组…

Android Fragment生命周期与Activity生命周期关系原理分析

一、整体概述 在 Android 开发中,Fragment 和 Activity 是构建用户界面的关键组件。Activity 作为应用的重要交互载体,管理着应用的整体界面和生命周期;而 Fragment 则是轻量级的 Activity,可嵌入到 Activity 中,实现…

Windows 系统下安装 RabbitMQ 的详细指南

Windows 系统下安装 RabbitMQ 的详细指南 Windows 系统下安装 RabbitMQ 的详细指南1. 前言2. 安装前的准备3. 安装步骤3.1 下载并安装 Erlang3.2 下载并安装 RabbitMQ3.3 配置环境变量3.4 验证安装3.5 启用 RabbitMQ 管理插件 4. 常见问题解决4.1 RabbitMQ 服务无法启动4.2 无法…

Python 性能优化:从入门到精通的实用指南

Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

【51单片机】程序实验14.I2C-EEPROM

主要参考学习资料:B站【普中官方】51单片机手把手教学视频 开发资料下载链接:http://www.prechin.cn/gongsixinwen/208.html 单片机套装:普中STC51单片机开发板A4标准版套餐7 目录 I2C介绍I2C物理层I2C协议层数据有效性规定起始和终止信号应答…

FB投广探秘:为何Facebook广告账户不消耗

在Facebook上投放广告时,您是否遇到过这种情况:广告创建完成后却发现账户没消耗,广告没跑出去?为什么会遇到这种情况?小编将结合最新行业动态,为你解析广告为何无消耗。 一、原因解析 1、账户余额不足 最直接的原因往往最容易被忽视。若…