CSRF 防护在企业级应用中需要考虑架构、性能、可扩展性和合规性等多个方面,以确保在复杂的环境中提供有效的安全保护。
企业级 CSRF 防护架构
1. 集中式 Token 管理
javascript// 集中式 Token 服务 class CentralizedTokenService { constructor(redisClient) { this.redis = redisClient; this.tokenExpiry = 3600; // 1 小时 } async generateToken(userId) { const token = crypto.randomBytes(32).toString('hex'); const key = `csrf:${userId}:${token}`; await this.redis.setex(key, this.tokenExpiry, '1'); return token; } async validateToken(userId, token) { const key = `csrf:${userId}:${token}`; const exists = await this.redis.exists(key); if (exists) { // 验证成功后删除 Token(一次性使用) await this.redis.del(key); return true; } return false; } async revokeUserTokens(userId) { const pattern = `csrf:${userId}:*`; const keys = await this.redis.keys(pattern); if (keys.length > 0) { await this.redis.del(...keys); } } }
2. 分布式环境下的 CSRF 防护
javascript// 分布式 CSRF 防护中间件 class DistributedCSRFProtection { constructor(tokenService, config) { this.tokenService = tokenService; this.config = config; } middleware() { return async (req, res, next) => { // 跳过安全方法 if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) { return next(); } // 获取用户 ID const userId = this.getUserId(req); if (!userId) { return res.status(401).send('Unauthorized'); } // 验证 Token const token = this.extractToken(req); if (!token) { return res.status(403).send('CSRF Token required'); } const isValid = await this.tokenService.validateToken(userId, token); if (!isValid) { return res.status(403).send('Invalid CSRF Token'); } next(); }; } getUserId(req) { // 从 Session 或 JWT 中获取用户 ID return req.user?.id || req.session?.userId; } extractToken(req) { // 从请求头或请求体中提取 Token return req.headers['x-csrf-token'] || req.body._csrf; } }
性能优化策略
1. Token 缓存
javascript// 使用 Redis 缓存 Token class CachedTokenService { constructor(redisClient, localCache) { this.redis = redisClient; this.localCache = localCache; this.ttl = 3600; } async getToken(userId) { // 首先检查本地缓存 const cachedToken = this.localCache.get(`csrf:${userId}`); if (cachedToken) { return cachedToken; } // 从 Redis 获取 const token = await this.redis.get(`csrf:${userId}`); if (token) { this.localCache.set(`csrf:${userId}`, token, this.ttl); return token; } // 生成新 Token const newToken = crypto.randomBytes(32).toString('hex'); await this.redis.setex(`csrf:${userId}`, this.ttl, newToken); this.localCache.set(`csrf:${userId}`, newToken, this.ttl); return newToken; } }
2. 批量 Token 验证
javascript// 批量验证多个请求的 Token class BatchTokenValidator { constructor(tokenService) { this.tokenService = tokenService; this.batchSize = 100; } async validateBatch(requests) { const results = []; for (let i = 0; i < requests.length; i += this.batchSize) { const batch = requests.slice(i, i + this.batchSize); const batchResults = await Promise.all( batch.map(req => this.validateSingle(req)) ); results.push(...batchResults); } return results; } async validateSingle(request) { const { userId, token } = request; const isValid = await this.tokenService.validateToken(userId, token); return { userId, token, isValid, timestamp: Date.now() }; } }
高可用性设计
1. Token 服务冗余
javascript// 多个 Token 服务的负载均衡 class RedundantTokenService { constructor(services) { this.services = services; this.currentService = 0; } async generateToken(userId) { const service = this.getNextService(); try { return await service.generateToken(userId); } catch (error) { // 尝试下一个服务 return await this.generateTokenWithRetry(userId, 3); } } async generateTokenWithRetry(userId, retries) { for (let i = 0; i < retries; i++) { const service = this.getNextService(); try { return await service.generateToken(userId); } catch (error) { if (i === retries - 1) { throw error; } } } } getNextService() { const service = this.services[this.currentService]; this.currentService = (this.currentService + 1) % this.services.length; return service; } }
2. 故障转移
javascript// 故障检测和转移 class FailoverTokenService { constructor(primaryService, backupService) { this.primary = primaryService; this.backup = backupService; this.isPrimaryHealthy = true; this.healthCheckInterval = 30000; // 30 秒 } startHealthCheck() { setInterval(async () => { try { await this.primary.ping(); this.isPrimaryHealthy = true; } catch (error) { console.error('Primary service unhealthy:', error); this.isPrimaryHealthy = false; } }, this.healthCheckInterval); } async generateToken(userId) { if (this.isPrimaryHealthy) { try { return await this.primary.generateToken(userId); } catch (error) { console.error('Primary service failed, using backup:', error); return await this.backup.generateToken(userId); } } return await this.backup.generateToken(userId); } }
合规性和审计
1. 审计日志
javascript// CSRF 操作审计日志 class CSRFAuditLogger { constructor(logService) { this.logService = logService; } async logTokenGeneration(userId, token, metadata) { const auditLog = { event: 'CSRF_TOKEN_GENERATED', userId, tokenHash: this.hashToken(token), timestamp: new Date().toISOString(), metadata: { ip: metadata.ip, userAgent: metadata.userAgent, sessionId: metadata.sessionId } }; await this.logService.log(auditLog); } async logTokenValidation(userId, token, isValid, metadata) { const auditLog = { event: 'CSRF_TOKEN_VALIDATED', userId, tokenHash: this.hashToken(token), isValid, timestamp: new Date().toISOString(), metadata: { ip: metadata.ip, userAgent: metadata.userAgent, sessionId: metadata.sessionId, requestPath: metadata.requestPath } }; await this.logService.log(auditLog); } hashToken(token) { return crypto.createHash('sha256').update(token).digest('hex'); } }
2. 合规性报告
javascript// 生成合规性报告 class ComplianceReportGenerator { constructor(auditLogger) { this.auditLogger = auditLogger; } async generateReport(startDate, endDate) { const logs = await this.auditLogger.getLogs(startDate, endDate); return { summary: { totalTokensGenerated: logs.filter(l => l.event === 'CSRF_TOKEN_GENERATED').length, totalValidations: logs.filter(l => l.event === 'CSRF_TOKEN_VALIDATED').length, failedValidations: logs.filter(l => l.event === 'CSRF_TOKEN_VALIDATED' && !l.isValid).length, uniqueUsers: new Set(logs.map(l => l.userId)).size }, failedAttempts: this.analyzeFailedAttempts(logs), suspiciousActivity: this.detectSuspiciousActivity(logs), complianceStatus: this.checkCompliance(logs) }; } analyzeFailedAttempts(logs) { const failedLogs = logs.filter(l => l.event === 'CSRF_TOKEN_VALIDATED' && !l.isValid); return { byUser: this.groupBy(failedLogs, 'userId'), byIP: this.groupBy(failedLogs, l => l.metadata.ip), byTime: this.groupByTime(failedLogs) }; } detectSuspiciousActivity(logs) { const suspicious = []; // 检测异常的验证失败率 const userFailureRates = this.calculateUserFailureRates(logs); Object.entries(userFailureRates).forEach(([userId, rate]) => { if (rate > 0.5) { // 失败率超过 50% suspicious.push({ type: 'HIGH_FAILURE_RATE', userId, rate }); } }); return suspicious; } checkCompliance(logs) { // 检查是否符合安全标准 const checks = { hasAuditLogs: logs.length > 0, hasTokenExpiry: true, // 需要从配置检查 hasSecureTransmission: true, // 需要从配置检查 hasProperValidation: true }; return { compliant: Object.values(checks).every(v => v), checks }; } }
监控和告警
1. 实时监控
javascript// CSRF 攻击实时监控 class CSRFMonitor { constructor(metricsService, alertService) { this.metrics = metricsService; this.alerts = alertService; this.thresholds = { failedValidationsPerMinute: 10, suspiciousIPRate: 5, unusualUserAgentRate: 3 }; } async monitorValidation(userId, token, isValid, metadata) { // 记录指标 this.metrics.increment('csrf.validations.total'); if (!isValid) { this.metrics.increment('csrf.validations.failed'); await this.checkFailureThresholds(userId, metadata); } else { this.metrics.increment('csrf.validations.success'); } } async checkFailureThresholds(userId, metadata) { const recentFailures = await this.getRecentFailures(60); // 最近 60 秒 if (recentFailures.length > this.thresholds.failedValidationsPerMinute) { await this.alerts.send({ severity: 'HIGH', message: 'High CSRF validation failure rate detected', details: { count: recentFailures.length, timeWindow: '60s' } }); } // 检查特定 IP 的失败率 const ipFailures = recentFailures.filter(f => f.metadata.ip === metadata.ip); if (ipFailures.length > this.thresholds.suspiciousIPRate) { await this.alerts.send({ severity: 'MEDIUM', message: 'Suspicious IP detected', details: { ip: metadata.ip, failures: ipFailures.length } }); } } }
2. 仪表板
javascript// CSRF 安全仪表板 class CSRFSecurityDashboard { constructor(monitor, reportGenerator) { this.monitor = monitor; this.reportGenerator = reportGenerator; } async getDashboardData(timeRange = '24h') { const report = await this.reportGenerator.generateReport( this.getStartDate(timeRange), new Date() ); const metrics = await this.monitor.getMetrics(timeRange); return { overview: { totalValidations: metrics.validations.total, successRate: this.calculateSuccessRate(metrics), activeUsers: report.summary.uniqueUsers }, security: { failedAttempts: report.summary.failedValidations, suspiciousActivity: report.suspiciousActivity.length, complianceStatus: report.complianceStatus.compliant }, trends: this.calculateTrends(metrics), alerts: this.getRecentAlerts() }; } }
企业级 CSRF 防护需要综合考虑架构、性能、可用性和合规性,构建一个全面、可靠的安全防护体系。