Skip to content

Instantly share code, notes, and snippets.

@j15e
Last active August 31, 2015 14:05
Show Gist options
  • Save j15e/95898dda12698eb6fd0e to your computer and use it in GitHub Desktop.
Save j15e/95898dda12698eb6fd0e to your computer and use it in GitHub Desktop.
Content Security Policy Violation Reporter
# Jean-Philippe Doyle, Copyright (c) 2015
# Licence MIT
# @see http://opensource.org/licenses/MIT
# Logs CSP report in rails logs sent to REPORT_URI
class CSPReportLogger
BLOCKED_URI_KEY = 'blocked-uri'.freeze
CSP_REPORT_KEY = 'csp-report'.freeze
IGNORE = %w{safari-extension://}.map { |src| /\A#{src}/.freeze }.freeze
LOG_HEADER = '[SECURITY] CSP Violation Report'.freeze
LOG_INVALID = 'INVALID FORMAT'.freeze
LOG_KEYS = %w{blocked-uri document-uri line-number source-file violated-directive}.freeze
POST_BODY = 'rack.input'.freeze
REPORT_METHOD = 'POST'.freeze
REPORT_URI = '/errors/csp'.freeze
REQUEST_UUID = 'action_dispatch.request_id'.freeze # rails-only too
def initialize(app)
@app = app
end
def call(env)
if REPORT_METHOD == env['REQUEST_METHOD'] && REPORT_URI == env['REQUEST_PATH']
report!(env)
[204, {}, []]
else
@app.call(env)
end
end
def report!(env)
report = JSON.parse(env[POST_BODY])[CSP_REPORT_KEY]
return log_invalid_body(env) if report.nil?
return if ignored?(report)
log(JSON.pretty_generate(report.slice(*LOG_KEYS)), env)
rescue JSON::ParserError
log_invalid_body(env)
end
private
def log_invalid_body(env)
log("#{LOG_INVALID}\n#{env[POST_BODY].read}", env)
end
def log(msg, env)
Rails.logger.info("[#{env[REQUEST_UUID]}}] #{LOG_HEADER}:\n#{msg}")
end
def ignored?(report)
return unless report[BLOCKED_URI_KEY]
IGNORE.any? { |d| d =~ report[BLOCKED_URI_KEY] }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment