【架构实战】API接口防刷与限流策略

一、接口防刷概述

接口防刷是保护系统安全的重要手段:

常见攻击:

  • 暴力破解密码
  • 恶意爬虫
  • 刷接口(抽奖、秒杀)
  • CC攻击

二、限流算法

1. 计数器算法

java 复制代码
@Component
public class CounterRateLimiter {
    
    public boolean tryAcquire(String key, int limit, int window) {
        String redisKey = "ratelimit:" + key;
        Long count = redisTemplate.opsForValue().increment(redisKey);
        
        if (count == 1) {
            redisTemplate.expire(redisKey, window, TimeUnit.SECONDS);
        }
        
        return count <= limit;
    }
}

2. 滑动窗口算法

java 复制代码
@Component
public class SlidingWindowRateLimiter {
    
    public boolean tryAcquire(String key, int limit, int window) {
        long now = System.currentTimeMillis();
        String redisKey = "ratelimit:sliding:" + key;
        
        // 移除窗口外的请求
        redisTemplate.opsForZSet().removeRangeByScore(
            redisKey, 0, now - window * 1000);
        
        // 当前请求数
        Long count = redisTemplate.opsForZSet().zCard(redisKey);
        
        if (count >= limit) {
            return false;
        }
        
        // 添加当前请求
        redisTemplate.opsForZSet().add(redisKey, now, now);
        redisTemplate.expire(redisKey, window * 2, TimeUnit.SECONDS);
        
        return true;
    }
}

3. 令牌桶算法

java 复制代码
@Component
public class TokenBucketRateLimiter {
    
    public boolean tryAcquire(String key, int bucketSize, int refillRate) {
        String redisKey = "tokenbucket:" + key;
        
        // 获取令牌
        Long tokens = redisTemplate.opsForValue().decrement(redisKey + ":tokens");
        
        if (tokens == null) {
            // 初始化令牌桶
            redisTemplate.opsForValue().set(redisKey + ":tokens", bucketSize - 1);
            redisTemplate.opsForValue().set(redisKey + ":last", System.currentTimeMillis());
            return true;
        }
        
        if (tokens < 0) {
            // 令牌不足
            return false;
        }
        
        return true;
    }
}

三、分布式限流

1. Lua脚本限流

java 复制代码
@Component
public class LuaRateLimiter {
    
    private static final String SCRIPT = """
        local key = KEYS[1]
        local limit = tonumber(ARGV[1])
        local window = tonumber(ARGV[2])
        
        local current = redis.call('INCR', key)
        
        if current == 1 then
            redis.call('EXPIRE', key, window)
        end
        
        if current > limit then
            return 0
        end
        
        return 1
        """;
    
    public boolean tryAcquire(String key, int limit, int window) {
        DefaultRedisScript<Long> script = new DefaultScript();
        script.setScriptText(SCRIPT);
        
        Long result = redisTemplate.execute(
            script,
            Collections.singletonList(key),
            String.valueOf(limit),
            String.valueOf(window)
        );
        
        return result != null && result == 1;
    }
}

2. Sentinel限流

java 复制代码
@Service
public class SentinelRateLimiter {
    
    @SentinelResource(value = "getOrder", blockHandler = "blockHandler")
    public Order getOrder(Long orderId) {
        return orderService.getById(orderId);
    }
    
    public Order blockHandler(Long orderId, BlockException e) {
        throw new BusinessException("请求过于频繁,请稍后重试");
    }
}

// 配置限流规则
@Configuration
public class SentinelConfig {
    
    @PostConstruct
    public void initRules() {
        List<FlowRule> rules = new ArrayList<>();
        
        FlowRule rule = new FlowRule();
        rule.setResource("getOrder");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(100);  // 每秒100次
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
        
        rules.add(rule);
        
        FlowRuleManager.loadRules(rules);
    }
}

四、接口防刷策略

1. 签名验证

java 复制代码
@Component
public class SignValidator {
    
    @Value("${app.secret}")
    private String appSecret;
    
    public boolean validateSign(Map<String, String> params, String sign) {
        // 1. 排序参数
        String sortedParams = params.entrySet().stream()
            .filter(e -> !e.getKey().equals("sign"))
            .sorted(Map.Entry.comparingByKey())
            .map(e -> e.getKey() + "=" + e.getValue())
            .collect(Collectors.joining("&"));
        
        // 2. 拼接密钥
        String signStr = sortedParams + "&key=" + appSecret;
        
        // 3. MD5签名
        String calculatedSign = MD5(signStr).toUpperCase();
        
        return calculatedSign.equals(sign.toUpperCase());
    }
}

2. 时间戳防重放

java 复制代码
@Component
public class TimestampValidator {
    
    private static final long MAX_TIMESTAMP_DIFF = 300000; // 5分钟
    
    public boolean validateTimestamp(long timestamp) {
        long now = System.currentTimeMillis();
        long diff = Math.abs(now - timestamp);
        return diff <= MAX_TIMESTAMP_DIFF;
    }
}

3. 唯一请求ID

java 复制代码
@Component
public class IdempotentChecker {
    
    public boolean check(String requestId) {
        String key = "idempotent:" + requestId;
        Boolean result = redisTemplate.opsForValue()
            .setIfAbsent(key, "1", 5, TimeUnit.MINUTES);
        
        return Boolean.TRUE.equals(result);
    }
}

五、验证码防护

1. 图形验证码

java 复制代码
@Service
public class CaptchaService {
    
    public Captcha generateCaptcha() {
        // 生成随机字符串
        String code = generateRandomCode(4);
        
        // 生成图片
        BufferedImage image = generateImage(code);
        
        // 生成唯一ID
        String captchaId = UUID.randomUUID().toString();
        
        // 存入Redis
        redisTemplate.opsForValue().set(
            "captcha:" + captchaId,
            code.toLowerCase(),
            5,
            TimeUnit.MINUTES
        );
        
        return new Captcha(captchaId, image);
    }
    
    public boolean verify(String captchaId, String code) {
        String cachedCode = (String) redisTemplate.opsForValue()
            .get("captcha:" + captchaId);
        
        if (cachedCode == null) {
            return false;
        }
        
        boolean valid = cachedCode.equalsIgnoreCase(code);
        
        if (valid) {
            redisTemplate.delete("captcha:" + captchaId);
        }
        
        return valid;
    }
}

2. 短信验证码

java 复制代码
@Service
public class SmsCodeService {
    
    public void sendSmsCode(String phone) {
        // 检查发送频率
        String sendKey = "sms:send:" + phone;
        Long sendCount = redisTemplate.opsForValue().increment(sendKey);
        
        if (sendCount != null && sendCount > 5) {
            throw new BusinessException("发送过于频繁,请1小时后再试");
        }
        
        if (sendCount == 1) {
            redisTemplate.expire(sendKey, 1, TimeUnit.HOURS);
        }
        
        // 生成6位验证码
        String code = String.format("%06d", new Random().nextInt(1000000));
        
        // 存入Redis
        String codeKey = "sms:code:" + phone;
        redisTemplate.opsForValue().set(codeKey, code, 5, TimeUnit.MINUTES);
        
        // 发送短信
        smsClient.send(phone, "验证码:" + code);
    }
}

六、IP限流

java 复制代码
@Component
public class IPRateLimiter {
    
    public boolean tryAcquire(String ip, String api, int limit, int window) {
        String key = "ip:ratelimit:" + ip + ":" + api;
        
        Long count = redisTemplate.opsForValue().increment(key);
        
        if (count == 1) {
            redisTemplate.expire(key, window, TimeUnit.SECONDS);
        }
        
        if (count > limit) {
            // 封禁IP
            blockIP(ip);
            return false;
        }
        
        return true;
    }
    
    private void blockIP(String ip) {
        String blockKey = "ip:block:" + ip;
        redisTemplate.opsForValue().set(blockKey, "1", 1, TimeUnit.HOURS);
    }
}

七、总结

接口防刷是系统安全的重要组成:

  • 限流算法:计数器、滑动窗口、令牌桶
  • 分布式限流:Lua脚本、Sentinel
  • 签名验证:防止请求被篡改
  • 验证码:防止机器攻击

最佳实践:

  1. 多层限流(网关+应用+数据库)
  2. 根据业务场景选择限流策略
  3. 做好监控和告警

个人观点,仅供参考

相关推荐
醇氧8 小时前
【Linux】Java 服务生产级部署指南:实现常驻后台、开机自启与系统服务化管理
java·开发语言
逻极8 小时前
Hermes Agent深度探索:一个会自我沉淀经验的终端智能体
架构·llm·agent·rag·多智能体系统·hermes agent·hermes
凡人叶枫8 小时前
Effective C++ 条款16:成对使用 new 和 delete 时要采取相同形式
开发语言·c++·effective c++
不吃土豆的马铃薯8 小时前
C++ 高性能网络缓冲区 Buffer 源码解析
linux·服务器·开发语言·网络·c++
数智顾问8 小时前
(151页PPT)XX集团信息化整体架构规划及ERP方案建议书(附下载方式)
大数据·架构
数据法师8 小时前
QuickSay :基于 Qt 的轻量级快捷短语管理工具
开发语言·qt
caimouse9 小时前
Reactos 第1章 概述
c语言·开发语言·架构
.千余9 小时前
【C++】C++继承入门(下):友元、静态成员与菱形继承的底层逻辑
开发语言·c++·笔记·学习·其他
财经资讯数据_灵砚智能9 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月10日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
namexingyun9 小时前
拆解Fable 5三重安全护栏:模型路由、蒸馏防护与生物安全分类器的技术原理 - 微元算力(weytoken)
java·人工智能·python·安全·架构·ai编程