Class: Otto::Security::CSP::ReportMiddleware
- Inherits:
-
Object
- Object
- Otto::Security::CSP::ReportMiddleware
- Defined in:
- lib/otto/security/csp/report_middleware.rb
Overview
Rack middleware that receives browser-posted Content-Security-Policy violation reports and dispatches them to an application callback.
This is the receiving half of Otto's CSP support; the emitting half is
Otto::Security::Config#generate_nonce_csp / Response#send_csp_headers
(and the static Otto::Security::Config#enable_csp!). When a report URI
is configured, the emitted policy carries a report-uri directive
pointing here.
Behavior (all mandatory for a public, unauthenticated receiver):
- INERT unless Otto::Security::Config#csp_report_uri is set. When it is not configured the middleware is a transparent pass-through.
- Only intercepts a POST whose path matches the configured report URI. Everything else (other paths, other methods) passes through untouched. The match is on the full request path (mount prefix included), since the report URI is the site-absolute path the browser POSTs to.
- Short-circuits BEFORE inner middleware, so CSRF, auth, and rate limiting never see the request. This is why browsers can POST reports with no CSRF token: the report never reaches the CSRF middleware. Otto::Security::Core#enable_csp_reporting! pins this middleware OUTERMOST (via the :outermost stack position), so the guarantee holds regardless of the order security features are enabled in. Only IPPrivacyMiddleware (pinned to the outer :entrypoint tier) runs ahead of it, and it is a pass-through. The flip side is that reports also bypass rate limiting — see the DoS note on Otto::Security::Core#enable_csp_reporting!; keep callbacks cheap.
- Enforces a hard MAX_BODY_BYTES body cap. Oversized bodies are
detected with a
cap + 1read and skipped WITHOUT parsing, so a hostile client cannot force large allocations against a public endpoint. - Parses both wire formats via Parser and invokes the registered callback once per normalized report.
- NEVER raises to the client and always responds
204 No Content(browsers ignore the body). A throwing callback is isolated by Otto::Security::Config#dispatch_csp_violation.
Constant Summary collapse
- MAX_BODY_BYTES =
Hard cap on the request body we are willing to read/parse. Browsers send small JSON documents; anything larger is abuse and is dropped.
64 * 1024
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, config = nil) ⇒ ReportMiddleware
constructor
64 KiB.
Constructor Details
#initialize(app, config = nil) ⇒ ReportMiddleware
64 KiB
50 51 52 53 |
# File 'lib/otto/security/csp/report_middleware.rb', line 50 def initialize(app, config = nil) @app = app @config = config || Otto::Security::Config.new end |
Instance Method Details
#call(env) ⇒ Object
55 56 57 58 59 |
# File 'lib/otto/security/csp/report_middleware.rb', line 55 def call(env) return @app.call(env) unless report_request?(env) receive_report(env) end |