web安全中的竞争条件(Race Condition)

前言

之前linux内核竞争条件漏洞"Dirty COW",直接导致了普通用户提权到root权限。这是系统级别的安全,然而web安全同样存在竞争条件漏洞场景

本文就谈谈web竞争条件漏洞的场景及修复

一、线程安全&竞争条件

1、先来看看线程安全,下段代码用两个线程操作一个公共变量infos

import threading

def thread1(info):
	for i in range(0,5000):
		info.append('1');

def thread2(info):
	info.append('a');

def multiprocess():
	infos = []
	t = threading.Thread(target=thread1, args=(infos,))
	t.start()

	t1 = threading.Thread(target=thread2, args=(infos,))
	t1.start()

	print(infos)

multiprocess()

因为list在python中是线程安全的,所以最终结果是a在列表最后。若线程不安全,线程1操作infos的过程中,可能会被中断,导致字符a被追加到infos的中间位置。

2、再来看看竞争条件

比如付费抽奖功能demo

def thread1_getyue(uid, has_money):
   has_money = getmoney(uid)#返回True/False
   
def thread2_choujiang(uid, has_money):
    if has_money:
        choujiang(uid)
        realpay(uid)#扣款    

def pay_and_luckdraw(uid):
    has_money = False
    thread1_getyue(uid, has_money)#查是否有余额,会改变has_money的值
    thread2_choujiang(uid, has_money)#先判断has_money,然后开始抽奖,跨系统处理,需要很长时间

(仅为展示竞争条件写的demo代码,实际过程中扣款失败可以撤销抽奖结果)

整个过程:判断余额 》抽奖流程 》扣款

如果攻击者的余额只够一次抽奖,若他高并发请求抽奖功能,试想下,第一请求正在处理抽奖流程时第二个请求也来了,这时还没扣款,has_money>0,所以第二请求也能进入抽奖流程。has_money成了竞争条件,余额不足也可以进行抽奖

3、其实,竞争条件问题不一定与线程安全相关,如下段顺序执行的代码

def pay_and_luckdraw(uid):
    has_money = getyue(uid)#查是否有余额
    if has_money>0:
        choujiang(uid)#开始抽奖,跨系统处理,需要很长时间,导致不能及时更改getyue返回状态
        realpay(uid)#扣款,会改变getyue返回结果

只要流程中有关键的三步:判断状态》进行操作》改变状态,就可能有竞争条件的问题

如果改成判断状态》改变状态》进行操作,就相当稳妥些。

比如付费抽奖这个功能,可以判断有余额后(状态),先扣费(改变状态),后抽奖(操作)。当然流程上可以增加更多异常判断

二、漏洞场景&修复

仔细分析下来,发现竞争条件问题关键点是多步操作中未考虑高并发的情况

所以很多有 判断状态》进行操作》改变状态 过程的功能都有可能存在问题,比如按天签到发奖励,付费抽奖等等

修复思路就是 “判断状态》改变状态》进行操作”,先改变状态后进行费时操作,充分考虑流程中的各种异常情况

你可能感兴趣的:(Web安全)