# frozen_string_literal: true class GenerateWafRulesJob < ApplicationJob queue_as :waf_rules def perform(event_id:) event = Event.find(event_id) # Only analyze blocked events for rule generation return unless event.blocked? # Generate different types of rules based on patterns generate_ip_rules(event) generate_path_rules(event) generate_user_agent_rules(event) generate_parameter_rules(event) # Broadcast rule updates globally ActionCable.server.broadcast("rules", { type: "refresh" }) rescue => e Rails.logger.error "Error generating WAF rules: #{e.message}" Rails.logger.error e.backtrace.join("\n") end private def generate_ip_rules(event) return unless event.ip_address.present? # Check if this IP has multiple violations violation_count = Event .by_ip(event.ip_address) .blocked .where(timestamp: 24.hours.ago..Time.current) .count # Log high-violation IPs - no automatic blocking without projects if violation_count >= 10 Rails.logger.info "IP with high violation count: #{event.ip_address} (#{violation_count} violations in 24 hours)" end end def generate_path_rules(event) return unless event.request_path.present? # Look for repeated attack patterns on specific paths path_violations = project.events .where(request_path: event.request_path) .blocked .where(timestamp: 1.hour.ago..Time.current) .count # Suggest path rules if 20+ violations on same path if path_violations >= 20 suggest_path_rule(project, event.request_path, path_violations) end end def generate_user_agent_rules(event) return unless event.user_agent.present? # Look for malicious user agents ua_violations = project.events .by_user_agent(event.user_agent) .blocked .where(timestamp: 1.hour.ago..Time.current) .count # Suggest user agent rules if 15+ violations from same UA if ua_violations >= 15 suggest_user_agent_rule(project, event.user_agent, ua_violations) end end def generate_parameter_rules(event) params = event.query_params return unless params.present? # Look for suspicious parameter patterns params.each do |key, value| next unless value.is_a?(String) # Check for common attack patterns in parameter values if contains_attack_pattern?(value) param_violations = project.events .where("payload LIKE ?", "%#{key}%#{value}%") .blocked .where(timestamp: 6.hours.ago..Time.current) .count if param_violations >= 5 suggest_parameter_rule(project, key, value, param_violations) end end end end def suggest_path_rule(project, path, violation_count) # Create an issue for manual review Issue.create!( project: project, title: "Suggested Path Rule", description: "Path '#{path}' has #{violation_count} violations in 1 hour", severity: "low", metadata: { type: "path_rule", path: path, violation_count: violation_count, suggested_action: "block" } ) end def suggest_user_agent_rule(project, user_agent, violation_count) # Create an issue for manual review Issue.create!( project: project, title: "Suggested User Agent Rule", description: "User Agent '#{user_agent}' has #{violation_count} violations in 1 hour", severity: "low", metadata: { type: "user_agent_rule", user_agent: user_agent, violation_count: violation_count, suggested_action: "block" } ) end def suggest_parameter_rule(project, param_name, param_value, violation_count) # Create an issue for manual review Issue.create!( project: project, title: "Suggested Parameter Rule", description: "Parameter '#{param_name}' with suspicious values has #{violation_count} violations", severity: "medium", metadata: { type: "parameter_rule", param_name: param_name, param_value: param_value, violation_count: violation_count, suggested_action: "block" } ) end def contains_attack_pattern?(value) # Common attack patterns attack_patterns = [ /