1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
| // 智能限流系统
class IntelligentRateLimiter {
constructor() {
this.redis = require('redis').createClient();
this.limiters = new Map();
this.adaptiveThresholds = new Map();
this.mlModel = null;
}
// 初始化机器学习模型
async initializeMLModel() {
// 使用TensorFlow.js加载预训练模型
const tf = require('@tensorflow/tfjs-node');
this.mlModel = await tf.loadLayersModel('file://./models/ddos_detection_model.h5');
}
// 滑动窗口限流器
async slidingWindowRateLimit(key, limit, windowMs) {
const now = Date.now();
const windowStart = now - windowMs;
const pipeline = this.redis.pipeline();
// 清理过期记录
pipeline.zremrangebyscore(key, 0, windowStart);
// 获取当前窗口内的请求数
pipeline.zcard(key);
// 添加当前请求
pipeline.zadd(key, now, `${now}-${Math.random()}`);
// 设置过期时间
pipeline.expire(key, Math.ceil(windowMs / 1000));
const results = await pipeline.exec();
const currentCount = results[1][1];
return {
allowed: currentCount < limit,
remaining: Math.max(0, limit - currentCount - 1),
resetTime: now + windowMs,
currentCount
};
}
// 令牌桶限流器
async tokenBucketRateLimit(key, capacity, refillRate) {
const now = Date.now();
const script = `
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local tokens = tonumber(ARGV[2])
local interval = tonumber(ARGV[3])
local now = tonumber(ARGV[4])
local bucket = redis.call('hmget', key, 'tokens', 'last_refill')
local current_tokens = tonumber(bucket[1]) or capacity
local last_refill = tonumber(bucket[2]) or now
-- 计算需要补充的令牌数
local elapsed = now - last_refill
local tokens_to_add = math.floor(elapsed / interval * tokens)
current_tokens = math.min(capacity, current_tokens + tokens_to_add)
-- 检查是否有足够的令牌
if current_tokens >= 1 then
current_tokens = current_tokens - 1
redis.call('hmset', key, 'tokens', current_tokens, 'last_refill', now)
redis.call('expire', key, math.ceil(capacity / tokens * interval))
return {1, current_tokens}
else
redis.call('hmset', key, 'tokens', current_tokens, 'last_refill', now)
redis.call('expire', key, math.ceil(capacity / tokens * interval))
return {0, current_tokens}
end
`;
const result = await this.redis.eval(script, 1, key, capacity, refillRate, 1000, now);
return {
allowed: result[0] === 1,
remaining: result[1],
capacity
};
}
// 自适应限流器
async adaptiveRateLimit(ip, endpoint, requestData) {
const key = `adaptive:${ip}:${endpoint}`;
// 获取历史数据
const history = await this.getRequestHistory(key, 3600000); // 最近1小时
// 使用机器学习模型预测攻击概率
const attackProbability = await this.predictAttackProbability(history, requestData);
// 根据攻击概率调整限流阈值
const baseLimit = this.getBaseLimit(endpoint);
const adaptiveLimit = Math.max(1, Math.floor(baseLimit * (1 - attackProbability)));
console.log(`Attack probability for ${ip}: ${attackProbability}, adaptive limit: ${adaptiveLimit}`);
return await this.slidingWindowRateLimit(key, adaptiveLimit, 60000);
}
// 预测攻击概率
async predictAttackProbability(history, requestData) {
if (!this.mlModel) {
// 如果模型未加载,使用简单的启发式规则
return this.heuristicAttackDetection(history, requestData);
}
const tf = require('@tensorflow/tfjs-node');
// 提取特征
const features = this.extractFeatures(history, requestData);
// 预测
const prediction = this.mlModel.predict(tf.tensor2d([features]));
const probability = prediction.dataSync()[0];
return probability;
}
// 启发式攻击检测
heuristicAttackDetection(history, requestData) {
const recentRequests = history.filter(req => Date.now() - req.timestamp < 60000);
const requestRate = recentRequests.length;
// 检测异常高的请求速率
if (requestRate > 100) return 0.8;
// 检测可疑的User-Agent
if (this.isSuspiciousUserAgent(requestData.userAgent)) return 0.6;
// 检测异常请求模式
if (this.hasAbnormalPattern(recentRequests)) return 0.7;
return 0.1; // 基础攻击概率
}
// 提取特征用于机器学习
extractFeatures(history, requestData) {
const recentMinute = history.filter(req => Date.now() - req.timestamp < 60000);
const recentHour = history.filter(req => Date.now() - req.timestamp < 3600000);
return [
recentMinute.length / 60, // 每秒请求数(最近1分钟)
recentHour.length / 3600, // 每秒请求数(最近1小时)
this.calculateUniqueIPs(recentHour), // 唯一IP数
this.calculateUniqueEndpoints(recentHour), // 唯一端点数
this.averageResponseTime(recentMinute), // 平均响应时间
this.errorRate(recentMinute), // 错误率
this.suspiciousUserAgentRatio(recentMinute), // 可疑User-Agent比例
this.requestSizeVariance(recentMinute), // 请求大小方差
this.calculateEntropy(recentMinute), // 请求熵
this.calculateBurstiness(recentMinute) // 请求突发性
];
}
// 集群限流器
async clusterRateLimit(key, limit, windowMs) {
const nodeId = process.env.NODE_ID || 'node1';
const clusterKey = `cluster:${key}`;
// 使用Redis的原子操作实现集群限流
const script = `
local key = KEYS[1]
local window = tonumber(ARGV[1])
local limit = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local node_id = ARGV[4]
-- 清理过期记录
redis.call('zremrangebyscore', key, 0, now - window)
-- 获取当前计数
local current = redis.call('zcard', key)
-- 检查是否超过限制
if current < limit then
-- 添加当前请求记录
redis.call('zadd', key, now, node_id .. ':' .. now)
redis.call('expire', key, math.ceil(window / 1000))
return {1, limit - current - 1}
else
return {0, 0}
end
`;
const result = await this.redis.eval(script, 1, clusterKey, windowMs, limit, Date.now(), nodeId);
return {
allowed: result[0] === 1,
remaining: result[1]
};
}
}
|