Django下防御Race Condition漏洞

今天下午在v2ex上看到一个帖子,讲述自己因为忘记加分布式锁导致了公司的损失:

Django下防御Race Condition漏洞_第1张图片

我曾在《从Pwnhub诞生聊Django安全编码》一文中描述过关于商城逻辑所涉及的安全问题,其中就包含并发漏洞(Race Condition)的防御,但当时说的比较简洁,也没有演示实际的攻击过程与危害。今天就以v2ex上这个帖子的场景来讲讲,常见的存在漏洞的Django代码,与我们如何正确防御竞争漏洞的方法。

0x01 Playground搭建

首先,使用我这个Django-Cookiecutter脚手架创建一个项目,项目名是Race Condition Playground。

创建两个新的Model:

class User(AbstractUser):
    username = models.CharField('username', max_length=256)
    email = models.EmailField('email', blank=True, unique=True)
    money = models.IntegerField('money', default=0)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'
        verbose_name = 'user'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username


class WithdrawLog(models.Model):
    user = models.ForeignKey('User', verbose_name='user', on_delete=models.SET_NULL, null=True)
    amount = models.IntegerField('amount')

    created_time = models.DateTimeField('created time', auto_now_add=True)
    last_modify_time = models.DateTimeField('last modify time', auto_now=True)

    class Meta:
        verbose_name = 'withdraw log'
        verbose_name_plural = 'withdraw logs'

    def __str__(self):
        return str(self.created_time)

一个是User表,用以储存用户,其中money字段是这个用户的余额;一个是WithdrawLog表,用以储存提取的日志。我们假设公司财务会根据这个日志表来向用户打款,那么只要成功在这个表中插入记录,则说明攻击成功。

然后,我们编写一个WithdrawForm,其字段amount,表示用户此时想提取的余额,必须是整数:

class WithdrawForm(forms.Form):
    amount = forms.IntegerField(min_value=1)

    def __init__(self, *args, **kw

你可能感兴趣的:(django,python,后端)