IP限流又双叒叕被绕过了?这5种实战方案让恶意请求无处遁形!

IP限流被绕过了?这5种实战方案让恶意请求无处遁形!

大家好,我是服务端技术精选的老司机,今天咱们聊聊一个让后端工程师又爱又恨的话题——IP限流

你是不是也遇到过这种崩溃场景:明明设置了接口限流,但还是被恶意请求给冲垮了?爬虫、刷单、DDOS攻击...各种"不速之客"轮番上阵,系统被搞得千疮百孔。

我曾经服务过一家在线教育平台,每天都有成千上万的爬虫在疯狂抓取课程信息,服务器资源被消耗殆尽,正常用户都无法访问。经过一番架构改造,我们实现了基于IP的多层限流体系,不仅挡住了恶意流量,还让系统性能提升了300%!

今天就把这套IP限流的实战方案全盘托出,让你的系统从此固若金汤!

一、为啥IP限流这么难搞?

1. IP获取的坑比你想象的多

很多同学以为IP限流很简单,不就是获取客户端IP然后计数嘛?Too young too simple!

在真实的生产环境中,获取真实IP就是第一道难关:

// 错误示例:直接获取RemoteAddr
String ip = request.getRemoteAddr(); // 这样拿到的可能是代理IP!

// 正确示例:考虑各种代理情况
public String getRealIp(HttpServletRequest request) {
    String ip = null;
    
    // 1. 先检查X-Forwarded-For头
    ip = request.getHeader("X-Forwarded-For");
    if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
        ip = ip.split(",")[0].trim();
    }
    
    // 2. 检查X-Real-IP头(Nginx常用)
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("X-Real-IP");
    }
    
    // 3. 最后才用RemoteAddr
    if (ip == null || ip.isEmpty()) {
        ip = request.getRemoteAddr();
    }
    
    return ip;
}

2. 攻击手段防不胜防

现在的攻击者越来越狡猾,常见的绕过手段有:

  • 代理池轮换:使用大量代理IP轮流访问
  • 分布式肉鸡:控制大量真实设备发起攻击
  • IP伪造:通过修改HTTP头伪造来源IP
  • 慢速攻击:控制请求频率,规避单纯的计数限流

我之前遇到过一个刷单团伙,他们使用了上万个住宅代理IP,每个IP每分钟只发3个请求,完美规避了我们的基础限流规则,差点把我们的优惠券薅光...

二、5种IP限流实战方案,从入门到精通

方案1:基础计数器限流 - 新手村装备

适用场景:小流量系统,简单防护

@Component
public class SimpleIpRateLimiter {
    
    // 使用本地缓存存储IP计数
    private final Cache<String, AtomicInteger> ipCountCache = 
        CacheBuilder.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(1, TimeUnit.MINUTES)
            .build();
    
    // 每分钟最多100次请求
    private static final int MAX_REQUESTS_PER_MINUTE = 100;
    
    public boolean isAllowed(String ip) {
        try {
            AtomicInteger count = ipCountCache.get(ip, AtomicInteger::new);
            return count.incrementAndGet() <= MAX_REQUESTS_PER_MINUTE;
        } catch (ExecutionException e) {
            return true; // 异常情况下放行
        }
    }
}

优点:实现简单,性能好
缺点:无法应对分布式环境,规则单一

方案2:Redis分布式限流 - 进阶装备

适用场景:分布式系统,中等流量

@Component 
public class RedisIpRateLimiter {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    public boolean isAllowed(String ip, int windowSize, int maxRequests) {
        String key = "rate_limit:ip:" + ip;
        long now = System.currentTimeMillis();
        long window = now - windowSize * 1000;
        
        // 使用Lua脚本保证原子性
        String luaScript = """
            local key = KEYS[1]
            local window = ARGV[1]
            local now = ARGV[2]
            local maxRequests = ARGV[3]
            
            -- 删除过期记录
            redis.call('zremrangebyscore', key, 0, window)
            
            -- 统计当前窗口内的请求数
            local current = redis.call('zcard', key)
            
            if current < tonumber(maxRequests) then
                redis.call('zadd', key, now, now)
                redis.call('expire', key, tonumber(ARGV[4]))
                return 1
            else
                return 0
            end
        """;
        
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(luaScript);
        script.setResultType(Long.class);
        
        Long result = redisTemplate.execute(script,
            Collections.singletonList(key),
            String.valueOf(window),
            String.valueOf(now),
            String.valueOf(maxRequests),
            String.valueOf(windowSize));
        
        return result != null && result == 1;
    }
}

方案3:分层限流 - 专业装备

适用场景:大流量系统,需要精细化控制

@Component
public class TieredIpRateLimiter {
    
    // 限流规则配置
    private static final Map<String, RateLimitRule> RULES = Map.of(
        "api", new RateLimitRule(100, 60),     // API接口:每分钟100次
        "login", new RateLimitRule(5, 300),    // 登录接口:每5分钟5次  
        "register", new RateLimitRule(3, 3600) // 注册接口:每小时3次
    );
    
    public boolean isAllowed(String ip, String endpoint) {
        RateLimitRule rule = RULES.get(endpoint);
        if (rule == null) return true;
        
        // 检查黑白名单
        if (isInBlacklist(ip)) return false;
        if (isInWhitelist(ip)) return true;
        
        // 应用限流规则
        return applyRateLimit(ip, endpoint, rule);
    }
    
    @Data
    @AllArgsConstructor
    public static class RateLimitRule {
        private int maxRequests;
        private int windowSize;
    }
}

方案4:智能动态限流 - 高级装备

适用场景:高流量系统,需要智能防护

@Component
public class SmartIpRateLimiter {
    
    public boolean smartRateLimit(String ip, String endpoint) {
        // 1. 获取系统当前负载
        double systemLoad = getSystemLoad();
        
        // 2. 获取IP的历史行为评分
        double ipScore = getIpBehaviorScore(ip);
        
        // 3. 动态计算限流阈值
        int baseLimit = getBaseLimit(endpoint);
        int dynamicLimit = calculateDynamicLimit(baseLimit, systemLoad, ipScore);
        
        // 4. 应用限流
        return applyDynamicRateLimit(ip, endpoint, dynamicLimit);
    }
    
    private double getSystemLoad() {
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        return osBean.getProcessCpuLoad();
    }
    
    private int calculateDynamicLimit(int baseLimit, double systemLoad, double ipScore) {
        // 系统负载越高,限流越严格
        double loadFactor = 1.0 - systemLoad * 0.5;
        // IP评分越低,限流越严格  
        double scoreFactor = ipScore;
        
        int dynamicLimit = (int) (baseLimit * loadFactor * scoreFactor);
        return Math.max(1, dynamicLimit);
    }
}

方案5:多维度综合限流 - 王者装备

适用场景:超大流量系统,需要全方位防护

@Component
public class ComprehensiveRateLimiter {
    
    public RateLimitResult isAllowed(RateLimitRequest request) {
        List<RateLimitResult> results = new ArrayList<>();
        
        // 1. IP维度限流
        results.add(checkIpRateLimit(request));
        
        // 2. 用户维度限流
        if (request.getUserId() != null) {
            results.add(checkUserRateLimit(request));
        }
        
        // 3. 设备指纹限流
        if (request.getDeviceFingerprint() != null) {
            results.add(checkDeviceRateLimit(request));
        }
        
        // 4. 综合判断
        return combineResults(results);
    }
    
    private RateLimitResult combineResults(List<RateLimitResult> results) {
        // 任何一个维度被限制,则整体被限制
        for (RateLimitResult result : results) {
            if (!result.isAllowed()) {
                return result;
            }
        }
        return RateLimitResult.allow();
    }
}

三、实战案例:某电商平台的反爬虫之战

背景

某电商平台每天遭受大量爬虫攻击,商品价格信息被大量抓取,服务器负载居高不下,正常用户体验受到严重影响。

解决方案

阶段一:基础防护

@Component
public class AntiCrawlerService {
    
    public boolean basicIpLimit(String ip) {
        // 普通用户:每分钟最多60次请求
        // 可疑IP:每分钟最多10次请求
        int limit = isSuspiciousIp(ip) ? 10 : 60;
        return simpleRateLimit(ip, 60, limit);
    }
    
    private boolean isSuspiciousIp(String ip) {
        return isProxyIp(ip) || hasAbnormalBehavior(ip);
    }
}

阶段二:行为分析

@Component  
public class BehaviorAnalyzer {
    
    public CrawlerRisk analyzeBehavior(String ip, HttpServletRequest request) {
        CrawlerRisk risk = new CrawlerRisk();
        
        // 1. User-Agent分析
        String userAgent = request.getHeader("User-Agent");
        if (isSuspiciousUserAgent(userAgent)) {
            risk.addScore(20);
        }
        
        // 2. 请求频率分析
        if (getRequestRate(ip) > 50) {
            risk.addScore(30);
        }
        
        return risk;
    }
}

效果

经过优化:

  • 爬虫流量从80%降至20%
  • 服务器CPU使用率从90%降至40%
  • 正常用户响应时间从3秒降至800ms
  • 月度带宽成本节省60%

四、IP限流的最佳实践

1. 分层防护策略

CDN → 防火墙 → 负载均衡 → 网关 → 应用

2. 多维度结合

不要只依赖IP,要结合:

  • 用户行为模式
  • 设备指纹
  • 地理位置
  • 时间窗口

3. 优雅降级

被限流时要给用户友好的提示:

@ControllerAdvice
public class RateLimitExceptionHandler {
    
    @ExceptionHandler(RateLimitException.class)
    public ResponseEntity<?> handleRateLimit(RateLimitException e) {
        return ResponseEntity.status(429).body(Map.of(
            "error", "请求过于频繁",
            "message", "请稍后再试",
            "retryAfter", e.getRetryAfter()
        ));
    }
}

4. 关键监控指标

  • IP限流触发次数
  • 黑名单IP数量
  • 限流误伤率
  • 系统响应时间

五、踩坑经验分享

坑1:忽略IPv6

很多同学只考虑IPv4,忘记了IPv6:

public boolean isValidIp(String ip) {
    return isValidIPv4(ip) || isValidIPv6(ip);
}

坑2:代理IP获取错误

要考虑多层代理的情况:

// X-Forwarded-For: client, proxy1, proxy2
String[] ips = xForwardedFor.split(",");
String clientIp = ips[0].trim(); // 第一个是真实客户端IP

坑3:误伤正常用户

  • 公司WiFi出口IP被限制,整个公司受影响
  • 小区宽带共享IP被封,整个小区用户受影响

解决方案:设置白名单,建立申诉机制

结语

IP限流是系统安全的第一道防线,但不是万能药。真正的安全防护需要:

  1. 多层防护:从网络层到应用层的全方位保护
  2. 智能识别:结合行为分析,精准识别恶意请求
  3. 动态调整:根据业务特点和系统负载动态优化
  4. 优雅降级:在保护系统的同时,不影响正常用户体验

记住老司机的一句话:"最好的限流,是让坏人感受到限制,让好人感受到保护"

觉得有用的话,点赞、在看、转发三连走起!下期我们聊聊如何设计一个高可用的分布式锁,敬请期待~


关注公众号:服务端技术精选
每周分享后端架构设计的实战经验,让技术更有温度!


标题:IP限流又双叒叕被绕过了?这5种实战方案让恶意请求无处遁形!
作者:jiangyi
地址:http://www.jiangyi.space/articles/2025/12/21/1766304296036.html

    0 评论
avatar