{T}

高安全架构 学习笔记(第 6 部分)

4.2 DDoS 攻击防护

DDoS 攻击类型

攻击类型攻击方式防护措施
流量攻击大量数据包拥塞带宽流量清洗、CDN
协议攻击耗尽服务器连接资源防火墙、负载均衡
应用层攻击针对应用层漏洞WAF、限流、验证码

防护实现

javascript
// DDoS 防护系统
class DDoSProtection {
  constructor() {
    this.requestCounts = new Map()
    this.blockedIPs = new Set()
    
    // 阈值配置
    this.thresholds = {
      requestsPerSecond: 100,
      requestsPerMinute: 1000,
      burstSize: 50
    }
  }
  
  // 请求限流中间件
  rateLimiter() {
    return (req, res, next) => {
      const ip = this.getClientIP(req)
      
      // 检查是否被封锁
      if (this.blockedIPs.has(ip)) {
        return res.status(429).json({
          error: 'Too Many Requests',
          message: '您的访问频率过高,已被暂时封锁'
        })
      }
      
      // 检查请求频率
      const checkResult = this.checkRateLimit(ip)
      
      if (!checkResult.allowed) {
        // 封锁 IP
        this.blockIP(ip, checkResult.reason)
        
        return res.status(429).json({
          error: 'Too Many Requests',
          message: '请求频率超过限制',
          retryAfter: checkResult.retryAfter
        })
      }
      
      next()
    }
  }
  
  // 检查请求频率
  checkRateLimit(ip) {
    const now = Date.now()
    const key = this.getRequestKey(ip)
    
    if (!this.requestCounts.has(key)) {
      this.requestCounts.set(key, {
        count: 1,
        firstRequest: now,
        lastRequest: now
      })
      
      return { allowed: true }
    }
    
    const record = this.requestCounts.get(key)
    const elapsed = now - record.firstRequest
    
    // 更新计数
    record.count++
    record.lastRequest = now
    
    // 每秒请求检查
    if (elapsed < 1000 && record.count > this.thresholds.requestsPerSecond) {
      return {
        allowed: false,
        reason: '每秒请求超过限制',
        retryAfter: 1000 - elapsed
      }
    }
    
    // 每分钟请求检查
    if (elapsed < 60000 && record.count > this.thresholds.requestsPerMinute) {
      return {
        allowed: false,
        reason: '每分钟请求超过限制',
        retryAfter: 60000 - elapsed
      }
    }
    
    // 重置计数器
    if (elapsed > 60000) {
      this.requestCounts.set(key, {
        count: 1,
        firstRequest: now,
        lastRequest: now
      })
    }
    
    return { allowed: true }
  }
  
  // 封锁 IP
  blockIP(ip, reason) {
    this.blockedIPs.add(ip)
    
    console.log(`封锁 IP: ${ip}, 原因: ${reason}`)
    
    // 自动解封(10分钟后)
    setTimeout(() => {
      this.blockedIPs.delete(ip)
      console.log(`解封 IP: ${ip}`)
    }, 600000)
  }
  
  // 验证码验证
  captchaVerification() {
    return async (req, res, next) => {
      const ip = this.getClientIP(req)
      
      // 检查是否需要验证码
      if (this.needsCaptcha(ip)) {
        const captcha = req.body.captcha
        
        if (!captcha || !(await this.verifyCaptcha(captcha))) {
          return res.status(400).json({
            error: 'Captcha Required',
            message: '需要验证码验证'
          })
        }
      }
      
      next()
    }
  }
  
  // 判断是否需要验证码
  needsCaptcha(ip) {
    const record = this.requestCounts.get(this.getRequestKey(ip))
    
    if (!record) return false
    
    // 超过阈值则需要验证码
    return record.count > this.thresholds.requestsPerMinute * 0.8
  }
  
  // 验证验证码
  async verifyCaptcha(captcha) {
    // 实际实现:调用验证码服务
    return true
  }
  
  // 辅助方法
  getClientIP(req) {
    return req.ip || req.connection.remoteAddress
  }
  
  getRequestKey(ip) {
    return `rate:${ip}`
  }
}

// 使用示例
const express = require('express')
const app = express()
const ddosProtection = new DDoSProtection()

// 应用限流中间件
app.use(ddosProtection.rateLimiter())

// 验证码验证
app.post('/api/sensitive', ddosProtection.captchaVerification(), (req, res) => {
  res.json({ message: '操作成功' })
})

app.listen(3000)