最难不过坚持丶渊洁 2023-11-22 15:54 采纳率: 75%
浏览 24

关于限流和防重的进一步思考

我发现我之前搞得一个东西不合理。

一. redis不能做防重,只能做限流和锁。因为对于一些场景:
1.比如转帐业务,如果用redis对用户id上锁。 那在规定时间内,他不能对不同用户做出转账操作。
2.如果一个按钮触发了多个防重接口,使用redis可能会出现死锁。
3.对于无记名用户下载等。redis也做不了。所以redis只适合限流。防止重放攻击和防重提交。不论有没有记名。
以上当然也可以通过独特的key名设计 如 接口_防重_userid. 来避免出现1,2不合理的情况,对于这个设计需要大量不同的key名,我们可以设置aop强制传递 接口名,userid,过期时间 解决。但3无法解决。

二. 还有方式是证书+时间戳。证书验证防篡改,时间戳验证防重。如果被重放攻击。时间戳相同,第二次重复提交失效。如果是刷新页面,那是新一次请求,不是防重任务,而是限流任务。 所以防重必须要有公证人,也就是https证书? 但是这个时间戳规定范围内依然可能受到重放攻击。

三. 为了解决在时间戳阈值内可能出现中间人不操作,只再转发重复提交信息的问题
使用nonce+证书+时间戳 这个nonce解决的应该是重复调用。 因为证书已经可以防止被修改。但无法防止在时间阈值内请求被调两次。所以加个nonce和web时间戳联合防重,那为啥不直接用nonce取代时间戳,我觉得是因为这个nonce的key名设计的是 web时间戳_防重 list集合存nonce。 等过60s阈值,再生产新的key。如果用nonce取代时间戳,那不知道什么时候删这批key。

上述工作可以直接放到过滤器中,也可和防刷结合在aop中。建议分开。逻辑通畅,而且防重针对所有接口比较好。防刷针对需要处理的接口。
那对于恶意刷流量的防治
我们可以在上述防重工作中进行id频次检查,针对频繁出现的加入黑名单,如在建立60s用户接口调用统计 userId_业务名 和使用限流器令牌桶对服务整体最大承受能力限制。

img

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-11-22 18:10
    关注

    【以下回答由 GPT 生成】

    关于使用Redis进行限流和防重的进一步思考

    问题分析

    根据问题描述,需要使用Redis进行限流和防重的优化,并且考虑到使用Redis锁定用户ID会导致用户无法对其他用户进行转账操作的问题。此外,还考虑到结合证书和时间戳进行验证来实现防重的需求。

    解决方案

    1. 限流

    使用Redis的令牌桶算法实现限流功能,可以控制每秒允许的请求次数。下面是一个使用Redis实现令牌桶算法的示例代码:

    import time
    import redis
    
    class RateLimiter:
        def __init__(self, redis_host, redis_port, max_requests, interval):
            self.redis_client = redis.Redis(host=redis_host, port=redis_port)
            self.max_requests = max_requests
            self.interval = interval
    
        def check_limit(self, key):
            current_timestamp = int(time.time())
            key_timestamp = self.redis_client.get(key)
            if not key_timestamp:
                self.redis_client.setex(key, self.interval, current_timestamp)
                return True
            else:
                if current_timestamp - int(key_timestamp) < self.interval:
                    return False
                else:
                    self.redis_client.setex(key, self.interval, current_timestamp)
                    return True
    

    使用示例:

    limiter = RateLimiter("localhost", 6379, 10, 1)  # 每秒最多允许10个请求
    
    if limiter.check_limit("user_123"):  # 根据用户ID进行限流
        # 执行业务逻辑
    else:
        # 返回限流错误信息
    
    2. 防重

    下面是一个使用Redis和时间戳实现防重的示例代码:

    import time
    import redis
    
    class DeduplicationChecker:
        def __init__(self, redis_host, redis_port, deduplication_window):
            self.redis_client = redis.Redis(host=redis_host, port=redis_port)
            self.deduplication_window = deduplication_window
    
        def check_duplicate(self, key):
            current_timestamp = int(time.time())
            key_timestamp = self.redis_client.get(key)
            if not key_timestamp:
                self.redis_client.setex(key, self.deduplication_window, current_timestamp)
                return False
            else:
                if current_timestamp - int(key_timestamp) < self.deduplication_window:
                    return True
                else:
                    self.redis_client.setex(key, self.deduplication_window, current_timestamp)
                    return False
    

    使用示例:

    checker = DeduplicationChecker("localhost", 6379, 60)  # 设置重复检测窗口为60秒
    
    if not checker.check_duplicate("transaction_123"):  # 根据交易ID进行防重
        # 执行业务逻辑
    else:
        # 返回重复提交错误信息
    
    3. 结合证书和时间戳进行验证

    在一些关键的业务场景中,对于防止篡改和重放攻击,结合证书和时间戳进行验证是一个有效的方案。具体实现可以参考以下步骤:

    • 使用HTTPS进行通信,确保数据的安全传输。
    • 在请求中包含证书,服务端验证证书的合法性,防止篡改攻击。
    • 在请求中包含时间戳,服务端验证时间戳的有效性,防止重放攻击。

    需要注意的是,对于时间戳的验证,可以使用上述防重的方法进行实现。但是,在实际应用中,还需要考虑时钟同步的问题,以及服务器时间可能与客户端时间存在差异的情况。

    4. 特殊情况下的刷新操作

    对于特殊情况下的刷新操作,可以根据具体业务需求进行处理。可以在服务器端添加逻辑判断,将刷新操作与防重任务进行区分,实现不同的处理逻辑。

    总结

    使用Redis进行限流和防重的优化可以通过令牌桶算法以及结合时间戳实现。对于防重的需求,可以借助Redis来实现,而不一定需要借助公证人。结合证书和时间戳进行验证可以提高防止篡改和重放攻击的效果。以上是一种可行的解决方案,在实际应用中可以根据具体场景进行调整和优化。



    【相关推荐】


    • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/739048
    • 除此之外, 这篇博客: 【Redis缓存】实现对缓存数据实现排序和分页功能中的        项目开发中往往会遇到一些查询逻辑较为复杂的报表,这些查询耗时动辄几十秒,甚至是几分钟,并且分页或排序时,往往是重新执行一遍SQL,效率低下。针对此情况,使用缓存能的解决例如排行榜和报表以及一些一致性要求不强的数据,并且对缓存数据结构的设计,可以实现对缓存数据的排序和分页功能,解决分页和排序时重新执行SQL的问题。 部分也许能够解决你的问题。

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 修改了问题 11月29日
  • 修改了问题 11月29日
  • 修改了问题 11月29日
  • 修改了问题 11月29日
  • 展开全部

悬赏问题

  • ¥50 potsgresql15备份问题
  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上