PHP代码展示的Race Condition漏洞例子

本文通过一个简单的PHP转账程序示例,解释了Race Condition漏洞的原理。在并发环境中,由于进程间的资源竞争,导致银行账户余额计算错误,从而揭示了这种常见编程错误的影响。

由于进程竞争相关资源(如CPU的运行时间等)导致的程序错误,称为Race Condition漏洞。

漏洞场景:简易转账程序,开始的时候bank1001账号有10000元钱,bank1002账号0元钱,每一次请求就从bank1001账号转账10元钱到bank1002账号。

创建数据库tmpbank,其中有一张表users,对应的SQL执行语句如下:

drop database if exists tmpbank;

create database tmpbank;

use tmpbank;

create table users(id varchar(50) primary key,number int);

insert usersvalues("bank1001",10000);

insert users values("bank1002",0);

对应的PHP代码如下:

functiongetnum($db,$id){

    $query="select * from users whereid='".$id."'";

    $result= mysqli_query($db,$query);

    $row=mysqli_fetch_assoc($result);

    return $row['number'];

}

functionupdate($db,$id,$num){

    $query="update users set number=$numwhere id='".$id."'";

    $result= mysqli_query($db,$query);

}

$from_id="bank1001";

$to_id="bank1002";

$num=1;

$db=mysqli_connect('localhost','root','123456','tmpbank');

$num1=getnum($db,"bank1001");

if($num1>1){

    update($db,$from_id,$num1-10);

    $num2=getnum($db,"bank1002");

    update($db,$to_id,$num2+10);

}

mysqli_close($db);

?>

下面再写一个并发请求的Python程序(程序在Ubuntu系统Python3运行正常,Windows系统不行—创建进程的方式不一样),代码如下:

importos

importrequests

print("start......");

os.fork()#2

os.fork()#4

os.fork()#8

os.fork()#16

os.fork()#32

os.fork()#64

os.fork()#128

ret=requests.get('http://127.0.0.1/test/t1.php')

按照PHP程序的基本逻辑,访问一次t1.php,则bank1001账号减少10元钱,而bank1002账号增加10元。每一个进程访问t1.php程序时,bank1001账号减少10元钱,而bank1002账号增加10元,Python并发程序同时开启128个进程,执行完成后,bank1001账号余额还有10000-1280=8720元,bank1002账号余额应该为1280元。实际运行结果如下(运行3次的不同结果,通过mysql数据库的控制台查看Python程序执行前和执行后的结果):

这是因为在并发的条件下,由于多个进程在竞争CPU时间时,出现了竞争条件漏洞。一个进程完成转账的基本核心操作步骤如下:

1 读取bank1001账号余额$num1;

2 将$num1-10,并更新bank1001账号余额;

3读取bank1002账号余额$num2;

4 将$num1-10,并更新bank1001账号余额。

在并发条件下,由于竞争CPU时间,一个进程可能没有处理完,另一个进程就会抢占CPU时间了,假设并发两个进程A和B,同时处理转账业务,则可能的执行顺序如下所示:

进程A和进程B交叉执行场景1:

A.1 读取bank1001账号余额(10000) 

A.2 更新bank1001账号余额(9990) 

A.3读取bank1002账号余额(0) 

B.1读取bank1001账号余额(9990)

B.2 更新bank1001账号余额(9980)

B.3读取bank1002账号余额(0)

A.4 更新bank1002账号余额(10) 

B.4 更新bank1002账号余额(10)

综合结果:bank1001账号余额9980(转出操作两次),bank1001账号余额10(B进程覆盖A进程的运行结果),这样钱的总数9980+10=9990少了10元。

进程A和进程B交叉执行场景2:

A.1 读取bank1001账号余额(10000) 

B.1读取bank1001账号余额(10000)

A.2 更新bank1001账号余额(9990) 

A.3读取bank1002账号余额(0) 

A.4 更新bank1002账号余额(10) 

B.2 更新bank1001账号余额(9990)

B.3读取bank1002账号余额(10)

B.4 更新bank1002账号余额(20)

综合结果:bank1001账号余额9990(B进程覆盖A进程的运行结果),bank1001账号余额20(转入操作两次),这样钱的总数9990+20=10010多了10元。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值