
【趣事】用 JavaScript 对抗 DDOS 攻击前言从一道面试题说起几年前我参加了一场前端面试面试官突然问我“如果让你用 JavaScript 写一个简单的 DDOS 防御工具你会怎么做”我愣了一下心想DDOS 攻击不是应该用防火墙、负载均衡这些后端工具吗JavaScript 这种运行在浏览器里的“玩具语言”能做什么后来我才发现这个问题其实藏着很多有趣的知识点。JavaScript 虽然不能直接防御服务器端的 DDOS但在客户端、在浏览器端它确实能做出一些巧妙的“反制”措施。今天我就带你从基础到进阶一步步探索这个有趣的话题。## 基础篇什么是 DDOS 攻击DDOSDistributed Denial of Service分布式拒绝服务攻击就像是一群坏蛋同时冲进一家超市把所有的购物车都抢走导致正常顾客无法购物。在互联网世界里攻击者会控制成千上万的“僵尸电脑”肉鸡向目标服务器发送海量请求直到服务器资源耗尽无法响应正常用户的请求。举个简单例子假设你的网站有一个搜索功能每次搜索都要查询数据库。如果攻击者用 10 万个浏览器同时发送搜索请求你的服务器很快就会崩溃。## 第一段代码创建一个简单的请求速率限制器JavaScript 可以在浏览器端实现一个“请求节流器”控制请求发送的频率。虽然这不能阻止攻击但可以保护用户自己不被“误伤”比如某些恶意脚本会频繁发送请求。javascript/** * 请求速率限制器 * 功能在指定时间窗口内限制请求次数 * 参数 * - maxRequests: 最大允许请求数 * - timeWindow: 时间窗口毫秒 */class RateLimiter { constructor(maxRequests 5, timeWindow 1000) { this.maxRequests maxRequests; // 每秒最多5次请求 this.timeWindow timeWindow; this.requestTimestamps []; // 记录每次请求的时间戳 } /** * 检查是否允许发送请求 * returns {boolean} true表示允许false表示拒绝 */ canSendRequest() { const now Date.now(); // 移除超出时间窗口的旧记录 this.requestTimestamps this.requestTimestamps.filter( timestamp now - timestamp this.timeWindow ); // 如果当前窗口内请求数未达上限允许请求 if (this.requestTimestamps.length this.maxRequests) { this.requestTimestamps.push(now); return true; } // 请求过于频繁拒绝 return false; } /** * 获取当前请求频率统计 * returns {object} 包含当前请求数和剩余时间 */ getStats() { const now Date.now(); const validRequests this.requestTimestamps.filter( timestamp now - timestamp this.timeWindow ); return { currentRequests: validRequests.length, maxRequests: this.maxRequests, remainingRequests: this.maxRequests - validRequests.length, timeWindow: this.timeWindow }; }}// 使用示例const limiter new RateLimiter(5, 1000); // 每秒最多5次请求// 模拟连续发送请求for (let i 0; i 10; i) { const allowed limiter.canSendRequest(); console.log(请求 ${i 1}: ${allowed ? ✅ 通过 : ❌ 被限制}); if (!allowed) { console.log(当前状态:, limiter.getStats()); }}这段代码虽然简单但它体现了防御 DDOS 的核心思想控制频率。在实际项目中我们可以将这个速率限制器挂载到 AJAX 请求发送前对用户的请求行为进行实时监控。## 进阶篇客户端验证码与行为分析仅仅限制频率还不够攻击者可能会用更复杂的脚本绕过。这时候就需要引入“行为验证”机制。常见的做法是让用户完成一个简单的任务比如点击按钮、拖拽滑块来证明“我是真人”。javascript/** * 基于行为分析的验证码系统 * 功能检测用户操作是否像“人类行为” * 原理人类点击有随机延迟机器人点击则非常规律 */class HumanVerification { constructor() { this.clickTimestamps []; // 记录点击时间戳 this.clickPositions []; // 记录点击位置 (x, y) this.verificationThreshold 0.7; // 人类行为概率阈值 } /** * 记录一次点击事件 * param {number} x - 点击位置的x坐标 * param {number} y - 点击位置的y坐标 */ recordClick(x, y) { this.clickTimestamps.push(Date.now()); this.clickPositions.push({ x, y }); // 只保留最近10次点击记录 if (this.clickTimestamps.length 10) { this.clickTimestamps.shift(); this.clickPositions.shift(); } } /** * 分析点击行为判断是否是真人 * returns {boolean} true表示像真人false表示像机器人 */ analyzeBehavior() { if (this.clickTimestamps.length 5) { return false; // 数据不足无法判断 } // 计算点击间隔的方差人类点击间隔变化较大 const intervals []; for (let i 1; i this.clickTimestamps.length; i) { intervals.push(this.clickTimestamps[i] - this.clickTimestamps[i-1]); } const mean intervals.reduce((a, b) a b, 0) / intervals.length; const variance intervals.reduce((sum, val) sum Math.pow(val - mean, 2), 0) / intervals.length; // 计算点击位置的变化率人类点击位置不会完全一致 const positions this.clickPositions; let positionVariation 0; for (let i 1; i positions.length; i) { const dx positions[i].x - positions[i-1].x; const dy positions[i].y - positions[i-1].y; positionVariation Math.sqrt(dx * dx dy * dy); } positionVariation / (positions.length - 1); // 结合两个指标计算人类概率 const humanScore (variance 100 ? 0.4 : 0) (positionVariation 20 ? 0.3 : 0); console.log(人类行为评分: ${humanScore.toFixed(2)} (阈值: ${this.verificationThreshold})); return humanScore this.verificationThreshold; } /** * 生成一个简单的验证挑战 * returns {string} 验证任务描述 */ createChallenge() { const challenges [ 请在5秒内点击页面上的红色按钮, 请将滑块拖到最右侧再松开, 请按顺序点击数字1、2、3 ]; return challenges[Math.floor(Math.random() * challenges.length)]; }}// 使用示例const verifier new HumanVerification();// 模拟人类用户点击console.log(模拟人类点击行为...);verifier.recordClick(100, 200);setTimeout(() verifier.recordClick(150, 220), 300);setTimeout(() verifier.recordClick(200, 180), 700);setTimeout(() verifier.recordClick(120, 250), 1200);setTimeout(() verifier.recordClick(180, 210), 1800);setTimeout(() { const isHuman verifier.analyzeBehavior(); console.log(判断结果: ${isHuman ? ✅ 是真人 : ❌ 可能是机器人}); console.log(验证挑战: ${verifier.createChallenge()});}, 2000);这段代码展示了一个有趣的思路通过分析用户的点击间隔和位置变化判断“行为模式”是否像人类。真实的 DDOS 防御系统会结合更多维度的数据比如鼠标移动轨迹、页面滚动速度、甚至键盘输入节奏。## 深入探索Web Workers 与请求分发当攻击请求量巨大时主线程可能会被阻塞。这时候我们可以利用 Web Workers 在后台线程处理请求过滤避免影响页面正常交互。javascript// worker.js - 在后台线程运行的请求过滤逻辑self.onmessage function(event) { const requestData event.data; // 简单的请求验证逻辑 function validateRequest(data) { // 检查请求间隔 const now Date.now(); if (data.lastRequestTime (now - data.lastRequestTime 50)) { return { allowed: false, reason: 请求过于频繁 }; } // 检查请求来源简单的IP伪造检测 if (data.userAgent data.userAgent.includes(bot)) { return { allowed: false, reason: 疑似自动化工具 }; } // 通过验证 return { allowed: true, reason: 正常请求 }; } const result validateRequest(requestData); self.postMessage(result);};// 主线程 - 创建Worker并发送请求const worker new Worker(worker.js);const requestQueue [];function sendFilteredRequest(url, data) { return new Promise((resolve, reject) { worker.onmessage function(event) { const result event.data; if (result.allowed) { // 通过验证实际发送请求 fetch(url, { method: POST, body: JSON.stringify(data), headers: { Content-Type: application/json } }) .then(response resolve(response)) .catch(error reject(error)); } else { reject(new Error(result.reason)); } }; worker.postMessage({ userAgent: navigator.userAgent, lastRequestTime: Date.now(), ...data }); });}// 使用示例async function testWorkerFilter() { try { const response await sendFilteredRequest(/api/data, { key: value }); console.log(请求成功:, response); } catch (error) { console.error(请求被拦截:, error.message); }}## 总结通过这篇文章我们从基础概念出发逐步探索了 JavaScript 在对抗 DDOS 攻击中的有趣应用。从简单的请求速率限制器到基于行为分析的验证码系统再到利用 Web Workers 进行后台过滤每一个技巧都展示了 JavaScript 在客户端安全领域的潜力。当然这些代码只是“趣味性”的尝试真正的 DDOS 防御需要结合后端、网络层、云防护等多层次手段。但通过这个项目我们可以学到-限流思想控制请求频率是防御的第一道防线-行为分析通过数据模式区分人类和机器-异步处理利用浏览器特性优化性能最后提醒一句学习这些技术是为了理解安全原理千万不要用来做坏事。真正的程序员会用技术保护世界而不是破坏它。希望这篇文章能激发你对网络安全和 JavaScript 潜力的更多思考