高频请求攻击如何限流

wen 网络安全 38

本文目录导读:

高频请求攻击如何限流

  1. 单机限流(针对单台服务器)
  2. 分布式限流(针对集群/微服务)
  3. 高级综合防御策略
  4. 部署与配置建议
  5. 应对高频攻击的推荐路线

高频请求攻击(如CC攻击、DDoS攻击)的核心是短时间内发送远超服务器处理能力的请求,限流是应对这类攻击最有效的手段之一,以下是几种主流的限流策略及其实现方式,按从简单到复杂、从单机到分布式的顺序排列:

单机限流(针对单台服务器)

这些方法适用于单机部署,或者在分布式系统中作为第一道防线。

  1. 计数器法(固定窗口)

    • 原理:将时间划分为固定窗口(如1秒),每个窗口内维护一个计数器,超过阈值则拒绝请求。
    • 缺点:存在“临界突变”问题,例如窗口为1秒,阈值100,如果在0.99秒和1.01秒各发送100个请求,系统会在0.001秒内承受200个请求,可能被冲垮。
    • 实现:使用 AtomicInteger + System.currentTimeMillis() / 时间窗口取模。
  2. 滑动窗口日志法

    • 原理:记录每次请求的时间戳,统计最近一个时间窗口内的请求数。
    • 优点:解决了固定窗口的临界问题。
    • 缺点:需要存储大量时间戳,内存消耗较大。
    • 实现:使用 Redis 的 Sorted Set(ZSet),以时间戳作为 score,通过 ZREMRANGEBYSCORE 删除过期记录,再用 ZCARD 统计数量。
  3. 令牌桶算法

    • 原理:以恒定速率向桶中添加令牌,请求需消耗一个令牌才能通过,桶有容量上限(应对突发流量)。
    • 优点:允许一定程度的突发请求,且能平滑整体请求速率。
    • 实现
      • 单机:Google Guava RateLimiter
      • 分布式:Redis 实现(get+set 或 Lua 脚本)。
  4. 漏桶算法

    • 原理:一个固定容量的桶,请求以任意速率流入,以固定速率流出(处理),若桶满,则请求被丢弃。
    • 优点:强制将请求速率稳定在固定值,能有效应对突发流量(直接丢弃超出的部分),非常适合保护下游系统。
    • 实现:Nginx limit_req 模块默认使用漏桶算法。

分布式限流(针对集群/微服务)

当服务部署在多台服务器时,单机限流会导致总吞吐量不准确,需要集中式存储。

  1. 基于 Redis 的滑动窗口(推荐)

    • 方案:结合 Redis 的 Sorted Set(有序集合)和时间戳,实现精确的分布式滑动窗口限流。

    • 伪代码思想

      -- Lua脚本 (保证原子性)
      local key = KEYS[1]
      local now = tonumber(ARGV[1])
      local window = tonumber(ARGV[2]) -- 窗口大小,如1000毫秒
      local limit = tonumber(ARGV[3])  -- 阈值
      -- 移除窗口之外的所有元素
      redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
      -- 获取当前窗口内请求数量
      local current = redis.call('ZCARD', key)
      if current >= limit then
          return 0 -- 限流
      else
          redis.call('ZADD', key, now, now) -- 加入当前请求
          redis.call('PEXPIRE', key, window) -- 设置过期时间
          return 1 -- 放行
      end
  2. 基于 Redis 的令牌桶

    • 方案:使用 Redis 的 GETSET 或 Lua 脚本维护令牌数量和时间差,计算应补充的令牌。
    • 注意:需要处理 Redis 单点故障,可用哨兵或集群模式。
  3. 网关层限流(推荐)

    • 方案:在流量进入微服务集群之前进行统一限流。
    • 工具:Nginx + limit_req 模块(基于漏桶)、OpenResty(Lua 脚本实现灵活的限流策略)、Spring Cloud Gateway / Zuul(配合 Redis 实现分布式限流)、KongEnvoy 等 API 网关。

高级综合防御策略

面对大规模高频攻击(如CC攻击),单靠限流可能不够,需要组合拳。

  1. 熔断与降级

    • 原理:当错误率或响应时间达到阈值时,直接切断对后端的调用,返回预设的回应(如“系统繁忙”)。
    • 工具:Hystrix(Netflix,已维护模式)、Resilience4j(推荐,Java)、Sentinel(阿里,功能强大,支持多种限流和熔断策略)。
  2. 用户/IP 分级限流

    • 策略
      • VIP用户:限流阈值高。
      • 普通用户:限流阈值低。
      • 非登录用户:限流阈值极低或直接拒绝高频访问。
    • 实现:请求头中提取用户ID或Token,结合Redis计数器。
  3. 验证码与黑名单

    • 验证码:当连续失败次数或请求频率超过低阈值时,强制要求输入验证码(图片、滑块、行为验证码)。
    • 动态黑名单:自动将触达限流阈值且判断为恶意(如访问不存在的URL、无Referer、User-Agent异常)的IP或用户加入黑名单(本地或Redis),一段时间内拒绝所有请求。
  4. AI/行为分析

    • 原理:分析用户的行为特征(如鼠标轨迹、点击间隔、页面浏览模式),识别出非人类的爬虫或攻击程序,需要引入机器学习或规则引擎。

部署与配置建议

  1. 多层防护

    • 外网入口:CDN + WAF(Web应用防火墙,可封杀IP和特征)。
    • 负载均衡/网关:Nginx limit_req 或网关限流。
    • 业务层:Redis分布式限流 + 熔断降级。
  2. 参数配置原则

    • 超时机制:设置合理的请求超时时间(如500ms),避免请求堆积。
    • 拒绝策略:返回友好的错误码(如 429 Too Many Requests),并在Response Header中加入 Retry-After
    • 动态调整:限流阈值不应写死,应支持通过配置中心(如 Nacos、Apollo)动态调整,以应对突发的正常流量(如秒杀)。

应对高频攻击的推荐路线

  1. 第一步(最低成本):在 Nginx 上启用 limit_req(漏桶算法)和 limit_conn(限制连接数),这是最直接、最有效的“止血”手段。
  2. 第二步(日常防护):在服务网关 (如Gateway/Nginx Lua) 或业务代码中,使用 Redis 滑动窗口 实现针对用户/IP的分布式限流。
  3. 第三步(复杂场景):引入 SentinelResilience4j 实现熔断、降级、热点参数限流。
  4. 第四步(终极手段):配合 WAFCDN行为验证码动态IP黑名单 进行立体防御。

抱歉,评论功能暂时关闭!