Module: Otto::Security::Core
- Included in:
- Otto
- Defined in:
- lib/otto/security/core.rb
Overview
Core security configuration methods included in the Otto class. Provides the public API for enabling and configuring security features.
Instance Method Summary collapse
-
#add_auth_strategy(name, strategy) ⇒ Object
Add an authentication strategy with a registered name.
-
#add_rate_limit_rule(name, options) ⇒ Object
Add a custom rate limiting rule.
-
#add_trusted_proxy(proxy) ⇒ Object
Add a trusted proxy server for accurate client IP detection.
-
#enable_csp!(policy = "default-src 'self'") ⇒ Object
Enable Content Security Policy (CSP) header to prevent XSS attacks.
-
#enable_csp_emission!(eager: false, development_mode: nil) ⇒ void
Mount Otto::Security::CSP::EmitMiddleware so nonce-based CSP headers are applied to responses by the framework instead of hand-rolled in each app.
-
#enable_csp_reporting!(report_uri, endpoint_url: nil) {|report| ... } ⇒ void
Enable turnkey Content Security Policy violation reporting.
-
#enable_csp_with_nonce!(debug: false) ⇒ Object
Enable Content Security Policy (CSP) with nonce support for dynamic header generation.
-
#enable_csrf_protection! ⇒ Object
Enable CSRF protection for POST, PUT, DELETE, and PATCH requests.
-
#enable_frame_protection!(option = 'SAMEORIGIN') ⇒ Object
Enable X-Frame-Options header to prevent clickjacking attacks.
-
#enable_hsts!(max_age: 31_536_000, include_subdomains: true) ⇒ Object
Enable HTTP Strict Transport Security (HSTS) header.
-
#enable_rate_limiting!(options = {}) ⇒ Object
Enable rate limiting to protect against abuse and DDoS attacks.
-
#enable_request_validation! ⇒ Object
Enable request validation including input sanitization, size limits, and protection against XSS and SQL injection attacks.
-
#set_security_headers(headers) ⇒ Object
Set custom security headers that will be added to all responses.
Instance Method Details
#add_auth_strategy(name, strategy) ⇒ Object
Add an authentication strategy with a registered name
This is the primary public API for registering authentication strategies.
The name you provide here will be available as strategy_result.strategy_name
in your application code, making it easy to identify which strategy authenticated
the current request.
Also available via Otto::Security::Configurator for consolidated security config.
247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/otto/security/core.rb', line 247 def add_auth_strategy(name, strategy) ensure_not_frozen! # Ensure auth_config is initialized (handles edge case where it might be nil) @auth_config = { auth_strategies: {}, default_auth_strategy: 'noauth' } if @auth_config.nil? # Strict mode: Detect strategy name collisions if @auth_config[:auth_strategies].key?(name) raise ArgumentError, "Authentication strategy '#{name}' is already registered" end @auth_config[:auth_strategies][name] = strategy end |
#add_rate_limit_rule(name, options) ⇒ Object
Add a custom rate limiting rule.
62 63 64 65 |
# File 'lib/otto/security/core.rb', line 62 def add_rate_limit_rule(name, ) ensure_not_frozen! @security_config.rate_limiting_config[:custom_rules][name.to_s] = end |
#add_trusted_proxy(proxy) ⇒ Object
Add a trusted proxy server for accurate client IP detection. Only requests from trusted proxies will have their forwarded headers honored.
74 75 76 77 |
# File 'lib/otto/security/core.rb', line 74 def add_trusted_proxy(proxy) ensure_not_frozen! @security_config.add_trusted_proxy(proxy) end |
#enable_csp!(policy = "default-src 'self'") ⇒ Object
Enable Content Security Policy (CSP) header to prevent XSS attacks. The default policy only allows resources from the same origin.
112 113 114 115 |
# File 'lib/otto/security/core.rb', line 112 def enable_csp!(policy = "default-src 'self'") ensure_not_frozen! @security_config.enable_csp!(policy) end |
#enable_csp_emission!(eager: false, development_mode: nil) ⇒ void
This method returns an undefined value.
Mount Otto::Security::CSP::EmitMiddleware so nonce-based CSP headers are applied to responses by the framework instead of hand-rolled in each app.
It is a passive backstop: it emits a nonce CSP only for responses that would otherwise ship without one, and never clobbers a policy a route already set. Enable nonce-CSP via #enable_csp_with_nonce! for it to emit anything — until then the middleware is INERT (a transparent pass-through), NOT an error. The two may be enabled in either order: both read the same security config, so mounting the backstop first and enabling nonce-CSP later works. Enable-order independence is why this does not raise when nonce-CSP is off.
By DEFAULT it is emit-if-consumed — it emits only when the request actually consumed a nonce (a view called Request#csp_nonce). This is the only safe blanket default: a nonce-only policy on a page that never stamped the nonce blocks every script.
163 164 165 166 167 168 |
# File 'lib/otto/security/core.rb', line 163 def enable_csp_emission!(eager: false, development_mode: nil) ensure_not_frozen! return if @middleware.includes?(Otto::Security::CSP::EmitMiddleware) @middleware.add(Otto::Security::CSP::EmitMiddleware, eager: eager, development_mode: development_mode) end |
#enable_csp_reporting!(report_uri, endpoint_url: nil) {|report| ... } ⇒ void
This method returns an undefined value.
Enable turnkey Content Security Policy violation reporting.
This is the receiving half of Otto’s CSP support. It:
1. Configures the report path (config.csp_report_uri = report_uri), so a
report-uri directive is appended to every emitted CSP policy (static
#enable_csp! and nonce #enable_csp_with_nonce! alike).
2. Registers your violation callback (if a block is given).
3. Injects Otto::Security::CSP::ReportMiddleware so browser POSTs to the
report path are received, parsed, and dispatched to the callback —
always answered with 204 and never touching your routes.
The middleware is pinned to run OUTERMOST (ahead of CSRF and every other middleware), so it short-circuits report POSTs before CSRF validation — browsers can post reports without a CSRF token. This holds regardless of the order in which you enable security features.
SECURITY / DoS: running outermost also means the receiver sits ahead of rate limiting (rate limiting is inner middleware). This is intentional — a public, unauthenticated report endpoint cannot depend on CSRF, session, or per-client throttling state — but it means a client can POST reports up to the 64 KiB body cap and invoke your callback on each one. Keep the callback cheap and bounded (sample or aggregate; avoid unbounded synchronous I/O), and put request-rate control for this path at the edge (reverse proxy / CDN / WAF) rather than expecting Otto to throttle it.
To (re)assign the callback later without touching the wiring, use the
config primitive directly: otto.security_config.on_csp_violation { ... }.
For modern browsers (which have deprecated report-uri), also pass
endpoint_url: — an ABSOLUTE URL whose path is report_uri. Otto then
emits a report-to directive plus a Reporting-Endpoints header so those
browsers deliver application/reports+json to the same receiver.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/otto/security/core.rb', line 216 def enable_csp_reporting!(report_uri, endpoint_url: nil, &block) ensure_not_frozen! @security_config.csp_report_uri = report_uri @security_config.csp_report_to_url = endpoint_url unless endpoint_url.nil? @security_config.on_csp_violation(&block) if block return if @middleware.includes?(Otto::Security::CSP::ReportMiddleware) # Pin OUTERMOST so it intercepts report POSTs ahead of CSRF regardless of # the order security features are enabled in. add_with_position fires the # stack's on_change callback, which rebuilds @app (wired in # Otto#initialize_core_state) — no explicit build_app! needed. @middleware.add_with_position(Otto::Security::CSP::ReportMiddleware, position: :outermost) end |
#enable_csp_with_nonce!(debug: false) ⇒ Object
Enable Content Security Policy (CSP) with nonce support for dynamic header generation. This enables the res.send_csp_headers response helper method.
133 134 135 136 |
# File 'lib/otto/security/core.rb', line 133 def enable_csp_with_nonce!(debug: false) ensure_not_frozen! @security_config.enable_csp_with_nonce!(debug: debug) end |
#enable_csrf_protection! ⇒ Object
Enable CSRF protection for POST, PUT, DELETE, and PATCH requests. This will automatically add CSRF tokens to HTML forms and validate them on unsafe HTTP methods.
16 17 18 19 20 21 22 |
# File 'lib/otto/security/core.rb', line 16 def enable_csrf_protection! ensure_not_frozen! return if @middleware.includes?(Otto::Security::Middleware::CSRFMiddleware) @security_config.enable_csrf_protection! use Otto::Security::Middleware::CSRFMiddleware end |
#enable_frame_protection!(option = 'SAMEORIGIN') ⇒ Object
Enable X-Frame-Options header to prevent clickjacking attacks.
122 123 124 125 |
# File 'lib/otto/security/core.rb', line 122 def enable_frame_protection!(option = 'SAMEORIGIN') ensure_not_frozen! @security_config.enable_frame_protection!(option) end |
#enable_hsts!(max_age: 31_536_000, include_subdomains: true) ⇒ Object
Enable HTTP Strict Transport Security (HSTS) header. WARNING: This can make your domain inaccessible if HTTPS is not properly configured. Only enable this when you’re certain HTTPS is working correctly.
101 102 103 104 |
# File 'lib/otto/security/core.rb', line 101 def enable_hsts!(max_age: 31_536_000, include_subdomains: true) ensure_not_frozen! @security_config.enable_hsts!(max_age: max_age, include_subdomains: include_subdomains) end |
#enable_rate_limiting!(options = {}) ⇒ Object
Enable rate limiting to protect against abuse and DDoS attacks. This will automatically add rate limiting rules based on client IP.
45 46 47 48 49 50 51 |
# File 'lib/otto/security/core.rb', line 45 def enable_rate_limiting!( = {}) ensure_not_frozen! return if @middleware.includes?(Otto::Security::Middleware::RateLimitMiddleware) @security.configure_rate_limiting() use Otto::Security::Middleware::RateLimitMiddleware end |
#enable_request_validation! ⇒ Object
Enable request validation including input sanitization, size limits, and protection against XSS and SQL injection attacks.
29 30 31 32 33 34 35 |
# File 'lib/otto/security/core.rb', line 29 def enable_request_validation! ensure_not_frozen! return if @middleware.includes?(Otto::Security::Middleware::ValidationMiddleware) @security_config.input_validation = true use Otto::Security::Middleware::ValidationMiddleware end |
#set_security_headers(headers) ⇒ Object
Set custom security headers that will be added to all responses. These merge with the default security headers.
88 89 90 91 |
# File 'lib/otto/security/core.rb', line 88 def set_security_headers(headers) ensure_not_frozen! @security_config.security_headers.merge!(headers) end |