58 lines
2.3 KiB
Ruby
58 lines
2.3 KiB
Ruby
module Api
|
|
class CspController < ApplicationController
|
|
# CSP violation reports don't need authentication
|
|
skip_before_action :verify_authenticity_token
|
|
allow_unauthenticated_access
|
|
|
|
# POST /api/csp-violation-report
|
|
def violation_report
|
|
# Parse CSP violation report
|
|
report_data = JSON.parse(request.body.read)
|
|
csp_report = report_data["csp-report"]
|
|
|
|
# Validate that we have a proper CSP report
|
|
unless csp_report.is_a?(Hash) && csp_report.present?
|
|
Rails.logger.warn "Received empty or invalid CSP violation report"
|
|
head :bad_request
|
|
return
|
|
end
|
|
|
|
# Log the violation for security monitoring
|
|
Rails.logger.warn "CSP Violation Report:"
|
|
Rails.logger.warn " Blocked URI: #{csp_report["blocked-uri"]}"
|
|
Rails.logger.warn " Document URI: #{csp_report["document-uri"]}"
|
|
Rails.logger.warn " Referrer: #{csp_report["referrer"]}"
|
|
Rails.logger.warn " Violated Directive: #{csp_report["violated-directive"]}"
|
|
Rails.logger.warn " Original Policy: #{csp_report["original-policy"]}"
|
|
Rails.logger.warn " User Agent: #{request.user_agent}"
|
|
Rails.logger.warn " IP Address: #{request.remote_ip}"
|
|
|
|
# Emit structured event for CSP violation
|
|
# This allows multiple subscribers to process the event (Sentry, local logging, etc.)
|
|
Rails.event.notify("csp.violation", {
|
|
blocked_uri: csp_report["blocked-uri"],
|
|
document_uri: csp_report["document-uri"],
|
|
referrer: csp_report["referrer"],
|
|
violated_directive: csp_report["violated-directive"],
|
|
original_policy: csp_report["original-policy"],
|
|
disposition: csp_report["disposition"],
|
|
effective_directive: csp_report["effective-directive"],
|
|
source_file: csp_report["source-file"],
|
|
line_number: csp_report["line-number"],
|
|
column_number: csp_report["column-number"],
|
|
status_code: csp_report["status-code"],
|
|
user_agent: request.user_agent,
|
|
ip_address: request.remote_ip,
|
|
current_user_id: Current.user&.id,
|
|
timestamp: Time.current,
|
|
session_id: Current.session&.id
|
|
})
|
|
|
|
head :no_content
|
|
rescue JSON::ParserError => e
|
|
Rails.logger.error "Invalid CSP violation report: #{e.message}"
|
|
head :bad_request
|
|
end
|
|
end
|
|
end
|