关于WEB资金系统转账的安全保护,防止极快的重复并发请求绕过系统余额不足的判断

发现很多项目都有一个漏洞:比如账户A有100元,账户B有0元,然后从账户A转100元给账户B,正常的代码流程是,先检测账户A余额是否足够,然后从账户A中扣除100元,再给账户B增加100元,结果变成账户A剩下0元,账户B剩下100元,转账操作成功,逻辑上并没有问题,但是,如果该转账请求瞬间执行30次,结果发现其中大约有4、5次都是成功的,其余的请求则会报余额不足,原因是那4、5次成功的请求中余额不足的判断是同一时间执行的,所以都可以通过,假如有5次都通过了,结果很有可能就变成,账户A扣除5×100元(余额-400元),账户B增加了5×100元(余额500元),这样问题就大了,我们期望的结果是,无论瞬间请求多少次都要保证只有一次可以通过余额不足的检测,那么解决的办法就是让这段代码队列执行。

在PHP中让代码队列执行最常用的方法就是非阻塞的文件排他锁,示例如下:

//非阻塞的文件排他锁
$fp = fopen("/lock.txt", "w+");
if(!flock($fp, LOCK_EX | LOCK_NB)){
	echo '系统繁忙';
	exit();
}
//读取用户余额,判断是否足够
//......
if(){  //余额足够
	//执行转账逻辑
	//......
	flock($fp, LOCK_UN);  //释放锁
	echo '转账成功';
}else{
	echo '余额不足';
}
fclose($fp);

发表评论

电子邮件地址不会被公开。 必填项已用*标注