基于行为的IP限流服务使用指南
🎯 概述
这是一个基于行为的分布式IP限流服务,专注于限制可疑行为而非正常请求频率。适用于多服务器部署和负载均衡环境。核心理念:
- 正常访问不限速 - 允许用户高频率正常访问
- 可疑行为记录 - 只有被安全规则拦截时才计数
- 行为阈值限流 - 超过可疑行为阈值则限流封禁
- 渐进式延迟 - 被限流的IP会有延迟惩罚,增加攻击成本
- 分布式共享 - 多个服务器实例共享限流状态
✨ 核心特性
- 🎯 行为导向 - 基于可疑行为而非请求频率限流
- 🌐 多服务器支持 - 适用于负载均衡、微服务环境
- 🚀 FusionCache 集成 - 本地缓存 + Redis 分布式缓存
- ⏰ UTC 时间统一 - 避免时区问题,确保跨服务器一致性
- 🔄 异步架构 - 所有缓存操作异步化,提升性能
- 🛡️ 安全延迟 - 对被限流的IP实施延迟惩罚
- 🗑️ 自动清理 - 依赖 FusionCache 自动过期机制
🚀 快速开始
1. 注册服务
// Program.cs 或 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// 首先确保已注册 FusionCache (通常在主项目中已配置)
services.AddFusionCache()
.WithDistributedCache(...)
.WithBackplane(...);
// 注册限流服务
services.AddScoped<IIpRateLimitService, IpRateLimitService>();
// 配置限流参数
services.Configure<RateLimitConfig>(config =>
{
config.WindowSizeMinutes = 5;
config.MaxBlocksPerWindow = 3;
config.BlockDurationMinutes = 30;
config.BlockedDelayBaseMs = 2000;
config.BlockedDelayMaxMs = 10000;
});
}
2. 配置中间件
public void Configure(IApplicationBuilder app)
{
// 添加限流中间件(必须在 RejectBots 之前)
app.UseMiddleware<RateLimitMiddleware>();
// 添加安全检查中间件
app.UseMiddleware<RejectBots>();
// 其他中间件
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { ... });
}
3. 配置文件示例
appsettings.json
{
"RateLimit": {
"WindowSizeMinutes": 5,
"MaxBlocksPerWindow": 3,
"BlockDurationMinutes": 30,
"CleanupIntervalMinutes": 60,
"BlockedDelayBaseMs": 2000,
"BlockedDelayMaxMs": 10000
}
}
🔧 配置参数详解
| 参数 | 默认值 | 说明 | 建议值 |
|---|---|---|---|
WindowSizeMinutes | 5 | 统计时间窗口(分钟) | 5-15分钟 |
MaxBlocksPerWindow | 3 | 窗口内最大拦截次数 | 3-5次 |
BlockDurationMinutes | 30 | 封禁持续时间(分钟) | 15-60分钟 |
CleanupIntervalMinutes | 60 | 清理间隔(分钟) | 30-120分钟 |
BlockedDelayBaseMs | 2000 | 被限流时的基础延迟(毫秒) | 1000-3000ms |
BlockedDelayMaxMs | 10000 | 被限流时的最大延迟(毫秒) | 5000-30000ms |
💡 行为限流策略说明
1. 核心理念
正常请求: 无限制,立即处理
可疑行为: 被 RejectBots 拦截时计数
达到阈值: 限流封禁,延迟处理所有请求
2. 限流触发条件
时间窗口: 5分钟内
拦截次数: 被安全规则拦截 3 次
限流时长: 30分钟
延迟处理: 2秒-10秒渐进式延迟
3. 延迟计算示例
配置: BlockedDelayBaseMs=2000, BlockedDelayMaxMs=10000
拦截次数 | 延迟时间
1-3 | 2000ms (基础延迟)
4-6 | 4000ms
7-9 | 6000ms
10+ | 10000ms (最大延迟)
4. 与传统限流的区别
传统限流: 限制所有请求频率
行为限流: 只限制可疑行为
例如:
- 正常用户快速浏览: ✅ 允许
- 正常API高频调用: ✅ 允许
- 访问非法路径: ❌ 计数
- 恶意爬虫行为: ❌ 计数
- SQL注入尝试: ❌ 计数
🌐 分布式架构
系统架构图
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 服务器 A │ │ 服务器 B │ │ 服务器 C │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ FusionCache │ │ │ │ FusionCache │ │ │ │ FusionCache │ │
│ │ (L1 Cache) │ │ │ │ (L1 Cache) │ │ │ │ (L1 Cache) │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
│ │ │
└──────────────────────┼──────────────────────┘
│
┌─────────────▼───────────┐
│ Redis Cluster │
│ (分布式缓存 + 消息) │
└─────────────────────────┘
请求处理流程
客户端请求
↓
RateLimitMiddleware
├─ 检查IP是否被限流
├─ 如被限流: 延迟 + 返回429
└─ 未限流: 继续处理
↓
RejectBots
├─ 安全规则检查
├─ 发现可疑行为: 调用 RecordBlockAsync()
└─ 正常请求: 继续处理
↓
业务逻辑处理
时间同步
- 所有服务器使用 UTC 时间
- 避免时区差异和夏令时问题
- 确保跨服务器时间计算一致
缓存键设计
缓存键格式: "RateLimit:IP:{IP地址}"
示例: "RateLimit:IP:192.168.1.100"
过期时间: 窗口大小 + 清理间隔(自动管理)
🔍 使用效果演示
正常请求流程
客户端请求 → 检查限流(通过) → 安全检查(通过) → 业务处理 → 返回结果
耗时: 正常业务处理时间(毫秒级)
可疑行为流程
客户端请求 → 检查限流(通过) → 安全检查(拦截) → 记录拦截 → 返回403
耗时: 毫秒级(不处理业务逻辑)
限流封禁流程
客户端请求 → 检查限流(拦截) → 延迟等待 → 返回429
耗时: 2-10秒延迟时间(惩罚机制)
📊 API 接口
核心接口
/// <summary>
/// 基于行为的IP限流服务接口
/// 专注于限制可疑行为,不限制正常请求频率
/// </summary>
public interface IIpRateLimitService
{
/// <summary>
/// 检查IP是否被限流
/// 只检查状态,不记录任何访问信息
/// </summary>
Task<RateLimitResult> CheckLimitStatusAsync(
string ip,
CancellationToken cancellationToken = default
);
/// <summary>
/// 记录IP被拦截事件
/// 当安全中间件检测到可疑行为时调用
/// </summary>
Task RecordBlockAsync(string ip, string? reason = null);
}
结果对象
/// <summary>
/// 基于行为的限流结果
/// 支持对被限流的请求进行延迟处理
/// </summary>
public class RateLimitResult
{
/// <summary>是否允许请求</summary>
public bool IsAllowed { get; init; }
/// <summary>是否被限流(需要延迟后返回429)</summary>
public bool IsBlocked { get; init; }
/// <summary>延迟时间(毫秒)- 仅在被限流时使用</summary>
public int DelayMs { get; init; }
/// <summary>结果消息</summary>
public string Message { get; init; } = string.Empty;
public static RateLimitResult Allow() => new() { IsAllowed = true };
public static RateLimitResult Block(string message, int delayMs = 0) =>
new()
{
IsAllowed = false,
IsBlocked = true,
Message = message,
DelayMs = delayMs
};
}
🛡️ 与 RejectBots 集成
集成架构
职责分离:
- RateLimitMiddleware: 专注限流检查和执行
- RejectBots: 专注安全规则检查和拦截记录
- 两者协同工作,实现基于行为的智能限流
RejectBots 集成示例
public class RejectBots
{
private readonly IIpRateLimitService _rateLimitService;
public async Task InvokeAsync(HttpContext context)
{
var clientIp = GetClientIp(context);
// 检查各种安全规则
if (IsOldBrowser(context))
{
await _rateLimitService.RecordBlockAsync(clientIp, "Old browser blocked");
await Response403Async(context);
return;
}
if (IsInBlacklist(context))
{
await _rateLimitService.RecordBlockAsync(clientIp, "Blacklist hit");
await Response403Async(context);
return;
}
if (IsEmptyUserAgent(context))
{
await _rateLimitService.RecordBlockAsync(clientIp, "Empty User-Agent");
await Response403Async(context);
return;
}
if (MatchesInterceptRules(context))
{
await _rateLimitService.RecordBlockAsync(clientIp, "Custom rule hit");
await Response403Async(context);
return;
}
await _next(context);
}
}
🔧 高级配置
1. 自定义延迟策略
public class CustomIpRateLimitService : IpRateLimitService
{
protected override int CalculateBlockedDelay(IpAccessRecord record)
{
// 自定义延迟计算逻辑
var baseDelay = _config.BlockedDelayBaseMs;
var maxDelay = _config.BlockedDelayMaxMs;
// 基于拦截次数的指数增长
var multiplier = Math.Pow(2, Math.Min(record.BlockCount - 1, 4));
var calculatedDelay = (int)(baseDelay * multiplier);
return Math.Min(calculatedDelay, maxDelay);
}
}
2. 白名单支持
public class WhitelistRateLimitService : IIpRateLimitService
{
private readonly HashSet<string> _whitelist = new()
{
"127.0.0.1", "::1", // 本地地址
"10.0.0.0/8", // 内网地址 (需要实现CIDR匹配)
};
public async Task<RateLimitResult> CheckLimitStatusAsync(
string ip,
CancellationToken cancellationToken = default)
{
if (IsWhitelisted(ip))
{
return RateLimitResult.Allow();
}
return await _baseService.CheckLimitStatusAsync(ip, cancellationToken);
}
public async Task RecordBlockAsync(string ip, string? reason = null)
{
if (!IsWhitelisted(ip))
{
await _baseService.RecordBlockAsync(ip, reason);
}
}
}
3. 监控和诊断
[ApiController]
public class DiagnosticsController : ControllerBase
{
private readonly IFusionCache _fusionCache;
[HttpGet("rate-limit/status/{ip}")]
public async Task<IActionResult> GetIpStatus(string ip)
{
var cacheKey = $"RateLimit:IP:{ip}";
var record = await _fusionCache.GetOrDefaultAsync<IpAccessRecord>(cacheKey);
if (record == null)
{
return Ok(new { Status = "Clean", Message = "No record found" });
}
return Ok(new
{
Status = record.BlockedUntil?.ToString("yyyy-MM-dd HH:mm:ss UTC"),
BlockCount = record.BlockCount,
WindowStart = record.WindowStart.ToString("yyyy-MM-dd HH:mm:ss UTC"),
LastBlockTime = record.LastBlockTime.ToString("yyyy-MM-dd HH:mm:ss UTC")
});
}
}
🎯 最佳实践
1. 部署建议
- 容器化部署: 所有容器使用 UTC 时区
- 负载均衡: 确保会话粘性不影响限流效果
- Redis 集群: 使用 Redis 集群保证高可用
- 监控报警: 监控限流触发频率和Redis连接状态
2. 配置调优
// 开发环境 - 较宽松的配置
WindowSizeMinutes = 10
MaxBlocksPerWindow = 5
BlockDurationMinutes = 15
// 生产环境 - 严格的配置
WindowSizeMinutes = 5
MaxBlocksPerWindow = 3
BlockDurationMinutes = 30
3. 日志配置建议
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Dpz.Core.Infrastructure.RateLimiting": "Information",
"FusionCache": "Warning"
}
}
}
4. 故障降级策略
public async Task<RateLimitResult> CheckLimitStatusAsync(
string ip,
CancellationToken cancellationToken = default)
{
try
{
return await _normalCheckLogic(ip, cancellationToken);
}
catch (Exception ex) when (ex is RedisException or TimeoutException)
{
_logger.LogWarning(ex, "限流服务降级,允许通过: {Ip}", ip);
// 降级策略:Redis不可用时允许通过
return RateLimitResult.Allow();
}
}
🚀 升级指南
从传统限流升级
- 概念转变: 从"频率限流"转为"行为限流"
- 配置调整: 移除
MaxRequestsPerWindow等频率相关配置 - 接口变更:
CheckAndApplyRateLimitAsync拆分为CheckLimitStatusAsync和RecordBlockAsync - 中间件顺序: 确保
RateLimitMiddleware在RejectBots之前
迁移步骤
// 旧版本调用
var result = await rateLimitService.CheckAndApplyRateLimitAsync(ip);
await rateLimitService.RecordAccessAsync(ip); // 移除此调用
// 新版本调用
var result = await rateLimitService.CheckLimitStatusAsync(ip);
// RecordBlockAsync 由 RejectBots 在检测到可疑行为时调用
📈 性能特点
- 高效检查: 只检查限流状态,不记录正常访问
- 本地缓存: FusionCache L1 缓存减少 Redis 访问
- 异步操作: 所有 I/O 操作异步化,提升并发性能
- 智能降级: Redis故障时自动降级,保证服务可用性
- 内存友好: 只存储被拦截IP的记录,大幅减少内存使用
🎉 总结
这个基于行为的分布式IP限流服务提供了:
- ✅ 智能限流: 只限制可疑行为,不影响正常用户
- ✅ 分布式支持: 适用于微服务、负载均衡环境
- ✅ 高性能: FusionCache 双层缓存架构
- ✅ 时区安全: 统一使用 UTC 时间
- ✅ 异步架构: 全异步操作,高并发友好
- ✅ 安全延迟: 对攻击者实施延迟惩罚
- ✅ 自动管理: 依赖 FusionCache 自动过期和清理
- ✅ 易于监控: 完整的日志和错误处理
通过这种基于行为的设计,你的应用既能有效防护恶意攻击,又能为正常用户提供无感的高性能体验!
评论加载中...