163 lines
4.7 KiB
Ruby
163 lines
4.7 KiB
Ruby
# 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 = [
|
|
/<script/i, # XSS
|
|
/union.*select/i, # SQL injection
|
|
/\.\./, # Directory traversal
|
|
/\/etc\/passwd/i, # File inclusion
|
|
/cmd\.exe/i, # Command injection
|
|
/eval\(/i, # Code injection
|
|
/javascript:/i, # JavaScript protocol
|
|
/onload=/i, # Event handler injection
|
|
]
|
|
|
|
attack_patterns.any? { |pattern| value.match?(pattern) }
|
|
end
|
|
end |