{T}

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

6.2 SQL 注入防护

SQL 注入攻击示例

javascript
//  不安全的 SQL 查询(存在注入风险)
const unsafeQuery = (username) => {
  const sql = `SELECT * FROM users WHERE username = '${username}'`
  // 攻击输入: ' OR '1'='1
  // 实际执行的 SQL: SELECT * FROM users WHERE username = '' OR '1'='1'
  // 结果:返回所有用户数据
}

//  安全的参数化查询
const safeQuery = async (username) => {
  const sql = 'SELECT * FROM users WHERE username = ?'
  const results = await db.query(sql, [username])
  return results
}

// SQL 注入防护类
class SQLInjectionProtection {
  constructor() {
    // 危险关键字黑名单
    this.blacklist = [
      'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'EXEC',
      'UNION', 'OR', 'AND', '--', ';', '/*', '*/'
    ]
    
    // 正则表达式检测
    this.patterns = [
      /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|EXEC)\b)/gi,
      /(UNION.*SELECT)/gi,
      /('|\")\s*(OR|AND)\s*('|\")/gi,
      /(;|--)/g,
      /(\/\*|\*\/)/g
    ]
  }
  
  // 检测 SQL 注入
  detect(input) {
    const detections = []
    
    // 黑名单检测
    for (const keyword of this.blacklist) {
      if (input.toUpperCase().includes(keyword)) {
        detections.push({
          type: 'blacklist',
          keyword,
          position: input.toUpperCase().indexOf(keyword)
        })
      }
    }
    
    // 正则表达式检测
    for (const pattern of this.patterns) {
      const matches = input.match(pattern)
      if (matches) {
        detections.push({
          type: 'pattern',
          pattern: pattern.toString(),
          matches
        })
      }
    }
    
    return {
      safe: detections.length === 0,
      detections
    }
  }
  
  // 清理输入
  sanitize(input) {
    let sanitized = input
    
    // 转义特殊字符
    sanitized = sanitized.replace(/'/g, "''")
    sanitized = sanitized.replace(/"/g, '\\"')
    sanitized = sanitized.replace(/\\/g, '\\\\')
    
    // 移除危险字符
    sanitized = sanitized.replace(/;/g, '')
    sanitized = sanitized.replace(/--/g, '')
    sanitized = sanitized.replace(/\/\*/g, '')
    sanitized = sanitized.replace(/\*\//g, '')
    
    return sanitized
  }
  
  // 防护中间件
  middleware() {
    return (req, res, next) => {
      // 检查请求参数
      const checkInput = (obj) => {
        for (const key in obj) {
          if (typeof obj[key] === 'string') {
            const result = this.detect(obj[key])
            
            if (!result.safe) {
              return res.status(400).json({
                error: 'SQL Injection Detected',
                message: '检测到潜在的 SQL 注入攻击',
                field: key
              })
            }
            
            // 清理输入
            obj[key] = this.sanitize(obj[key])
          } else if (typeof obj[key] === 'object') {
            checkInput(obj[key])
          }
        }
      }
      
      checkInput(req.body)
      checkInput(req.query)
      checkInput(req.params)
      
      next()
    }
  }
}