高并发下的漏洞(条件竞争)

下面我通过一个充值业务来剖析高并发漏洞

1、用户提交充值码

2、数据库查询该码,如果查到库里有这个码并且码未被消费过,则走到第3步的逻辑里,否则返回code not useful

3、更新码的状态,更新消费该码的用户,

4、更新用户的余额,比如兑换的充值码为20元,用户money字段增加20

@user_blue.route('/exchange',methods=['POST'])
@user_auth
def exchange():
    data =  request.json
    code = data.get('code') #1.用户提交充值码
    try:
        flag = Flag.query.filter_by(code=code).first() #数据库查询该码
        if not flag or flag.isused is True: #表示无该充值码或该码已被消费过
            return {"code":40001,"msg":"code not useful"}
        else: 
            flag.used_id = session.get('uid')  #设置消费该码的用户
            flag.isused = True  #将该码的状态更新为已使用
            db.session.add(flag)
            db.session.commit()
            return jsonify({"msg":"exchange success"})
    except Exception as e:
        db.session.rollback()
        raise e

这里的代码我先把第4步省略了

接下来我们来兑换一下充值码:880099 

可以看到,该码的isused已经被更新成True(已使用),关联用户(userid=1)

所以当我们再次使用该码进行充值时,提示code not useful

那么这里有什么安全问题呢?现代化的应用都是多线程的,例如服务端支持10个多线程。

gunicorn -w4 -t10 -b0.0.0.0:5000 app:app

那么我发送6个并发请求过去,会发生什么呢?

兑换成功4次,失败2次。

通过SQL日志分析,并发请求了6次,后端创建了6个数据库事务(Engine BEGIN)。有4次COMMIT,2次ROLLBACK

下面,我完善了第4步,增加用余额

@user_blue.route('/exchange',methods=['POST'])
@user_auth
def exchange():
    data =  request.json
    code = data.get('code')
    try:
        flag = Flag.query.filter_by(code=code).first()
        if not flag or flag.isused is True: #表示无该充值码不可用
            return {"code":40001,"msg":"code not useful"}
        else:
            flag.user_id = session.get('uid')
            flag.isused = True
            db.session.add(flag)
            db.session.commit()
            user = User.query.filter_by(id=user_id).first()
            '''增加用户余额'''
            user.money = user.money+flag.price
            db.session.add(user)
            db.session.commit()
            return jsonify({"code":10001,"msg":"exchange success"})
    except Exception as e:
        db.session.rollback()
        raise e

使用该充值码进行高并发充值

minzhizhou这个号当前余额为0

 用burp Turbo Intruder插件进行30个并发请求

可以看到,8次兑换成功,那么看一下账户余额是不是160

 余额只有80,和预期的不太一样,但有一点是肯定的,一个码被兑换了多次。

看一下SQL日志,可以看到有好几个rollback. 这是因为数据库事务的隔离性导致。

隔离性有4种,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。关于数据库事务的更多内容可以参阅:再谈数据库事务隔离性_51CTO博客_数据库隔离性,这篇文章已经解释很详细了。

漏洞环境已同步到:https://api.itner.net

目前包含的漏洞场景如下:

1、 兑换充值码的高并发漏洞(一码多换)

2、 登陆暴力破解漏洞

3、CSRF添加管理员账号

4、 微信小程序泄漏session_key

5、评论区XSS

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ConcurrentHashMap 是 Java 中用于支持高并发操作的线程安全的哈希表实现。然而,在高并发环境下,仍然存在一些问题需要注意。 1. 首先,虽然 ConcurrentHashMap 是线程安全的,但并不意味着所有操作都是原子性的。例如,putIfAbsent() 方法是原子性的,但是其他操作(如 get、put、remove)可能需要对同一个桶进行多次读取或写入,这可能会导致竞争条件和数据不一致性。 2. 其次,当多个线程同时对 ConcurrentHashMap 进行修改时,可能会出现数据不一致的情况。因为 ConcurrentHashMap 内部使用了分段锁(Segment),每个 Segment 维护了一个独立的哈希表,不同的线程可以同时对不同的 Segment 进行修改,从而提高并发性能。但是,如果多个线程同时对同一个 Segment 进行修改,仍然需要通过锁来保证线程安全。 3. 另外,ConcurrentHashMap 的迭代器并不是强一致的。在迭代过程中,如果有其他线程同时对 ConcurrentHashMap 进行修改,可能会导致迭代结果不准确或抛出异常。为了解决这个问题,可以使用 ConcurrentHashMap 的 keySet()、values() 或 entrySet() 方法返回的视图进行安全的迭代操作。 为了更好地处理高并发下的问题,可以采取以下措施: 1. 尽量减少对同一个桶的并发修改,避免竞争条件和数据不一致性的问题。 2. 使用适当的并发级别(concurrencyLevel)初始化 ConcurrentHashMap,以平衡并发性能和内存开销。 3. 在迭代操作时,使用 ConcurrentHashMap 提供的安全视图进行操作,例如 keySet()、values() 或 entrySet() 返回的集合。 4. 如果需要更高的并发性能,可以考虑使用其他并发容器,如 ConcurrentSkipListMap 或 ConcurrentHashMap 的非阻塞版本 LongAdder。 总之,虽然 ConcurrentHashMap 是线程安全并发容器,但在高并发环境下仍然需要注意竞争条件、数据不一致性和迭代安全等问题。合理使用并发容器,并采取相应的措施,可以提高系统的并发性能和数据一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信息安全笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值