Class: Otto::Security::Config
- Inherits:
-
Object
- Object
- Otto::Security::Config
- Defined in:
- lib/otto/security/config.rb
Overview
Security configuration for Otto applications
This class manages all security-related settings including CSRF protection, input validation, trusted proxies, and security headers. Security features are disabled by default for backward compatibility.
Instance Attribute Summary collapse
-
#csp_nonce_enabled ⇒ Object
Returns the value of attribute csp_nonce_enabled.
-
#csrf_header_key ⇒ Object
Returns the value of attribute csrf_header_key.
-
#csrf_protection ⇒ Object
Returns the value of attribute csrf_protection.
-
#csrf_session_key ⇒ Object
Returns the value of attribute csrf_session_key.
-
#csrf_token_key ⇒ Object
Returns the value of attribute csrf_token_key.
-
#debug_csp ⇒ Object
Returns the value of attribute debug_csp.
-
#input_validation ⇒ Object
Returns the value of attribute input_validation.
-
#max_param_depth ⇒ Object
Returns the value of attribute max_param_depth.
-
#max_param_keys ⇒ Object
Returns the value of attribute max_param_keys.
-
#max_request_size ⇒ Object
Returns the value of attribute max_request_size.
-
#require_secure_cookies ⇒ Object
Returns the value of attribute require_secure_cookies.
-
#security_headers ⇒ Object
Returns the value of attribute security_headers.
-
#trusted_proxies ⇒ Object
Returns the value of attribute trusted_proxies.
Instance Method Summary collapse
-
#add_trusted_proxy(proxy) ⇒ void
Add a trusted proxy server for accurate client IP detection.
-
#csp_nonce_enabled? ⇒ Boolean
Check if CSP nonce support is enabled.
-
#csrf_enabled? ⇒ Boolean
Check if CSRF protection is currently enabled.
-
#debug_csp? ⇒ Boolean
Check if CSP debug logging is enabled.
-
#disable_csp_nonce! ⇒ void
Disable CSP nonce support.
-
#disable_csrf_protection! ⇒ void
Disable CSRF protection.
-
#enable_csp!(policy = "default-src 'self'") ⇒ void
Enable Content Security Policy (CSP) header.
-
#enable_csp_with_nonce!(debug: false) ⇒ void
Enable Content Security Policy (CSP) with nonce support.
-
#enable_csrf_protection! ⇒ void
Enable CSRF (Cross-Site Request Forgery) protection.
-
#enable_frame_protection!(option = 'SAMEORIGIN') ⇒ void
Enable X-Frame-Options header to prevent clickjacking.
-
#enable_hsts!(max_age: 31_536_000, include_subdomains: true) ⇒ void
Enable HTTP Strict Transport Security (HSTS) header.
- #generate_csrf_token(session_id = nil) ⇒ Object
-
#generate_nonce_csp(nonce, development_mode: false) ⇒ String
Generate a CSP policy string with the provided nonce.
- #get_or_create_session_id(request) ⇒ Object
-
#initialize ⇒ Config
constructor
Initialize security configuration with safe defaults.
-
#set_custom_headers(headers) ⇒ void
Set custom security headers.
-
#trusted_proxy?(ip) ⇒ Boolean
Check if an IP address is from a trusted proxy.
-
#validate_request_size(content_length) ⇒ Boolean
Validate that a request size is within acceptable limits.
- #verify_csrf_token(token, session_id = nil) ⇒ Object
Constructor Details
#initialize ⇒ Config
Initialize security configuration with safe defaults
All security features are disabled by default to maintain backward compatibility with existing Otto applications.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/otto/security/config.rb', line 34 def initialize @csrf_protection = false @csrf_token_key = '_csrf_token' @csrf_header_key = 'HTTP_X_CSRF_TOKEN' @csrf_session_key = '_csrf_session_id' @max_request_size = 10 * 1024 * 1024 # 10MB @max_param_depth = 32 @max_param_keys = 64 @trusted_proxies = [] @require_secure_cookies = false @security_headers = default_security_headers @input_validation = true @csp_nonce_enabled = false @debug_csp = false end |
Instance Attribute Details
#csp_nonce_enabled ⇒ Object
Returns the value of attribute csp_nonce_enabled.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def csp_nonce_enabled @csp_nonce_enabled end |
#csrf_header_key ⇒ Object
Returns the value of attribute csrf_header_key.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def csrf_header_key @csrf_header_key end |
#csrf_protection ⇒ Object
Returns the value of attribute csrf_protection.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def csrf_protection @csrf_protection end |
#csrf_session_key ⇒ Object
Returns the value of attribute csrf_session_key.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def csrf_session_key @csrf_session_key end |
#csrf_token_key ⇒ Object
Returns the value of attribute csrf_token_key.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def csrf_token_key @csrf_token_key end |
#debug_csp ⇒ Object
Returns the value of attribute debug_csp.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def debug_csp @debug_csp end |
#input_validation ⇒ Object
Returns the value of attribute input_validation.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def input_validation @input_validation end |
#max_param_depth ⇒ Object
Returns the value of attribute max_param_depth.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def max_param_depth @max_param_depth end |
#max_param_keys ⇒ Object
Returns the value of attribute max_param_keys.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def max_param_keys @max_param_keys end |
#max_request_size ⇒ Object
Returns the value of attribute max_request_size.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def max_request_size @max_request_size end |
#require_secure_cookies ⇒ Object
Returns the value of attribute require_secure_cookies.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def @require_secure_cookies end |
#security_headers ⇒ Object
Returns the value of attribute security_headers.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def security_headers @security_headers end |
#trusted_proxies ⇒ Object
Returns the value of attribute trusted_proxies.
24 25 26 |
# File 'lib/otto/security/config.rb', line 24 def trusted_proxies @trusted_proxies end |
Instance Method Details
#add_trusted_proxy(proxy) ⇒ void
This method returns an undefined value.
Add a trusted proxy server for accurate client IP detection
Only requests from trusted proxies will have their X-Forwarded-For and similar headers honored for IP detection. This prevents IP spoofing from untrusted sources.
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/otto/security/config.rb', line 95 def add_trusted_proxy(proxy) case proxy when String @trusted_proxies << proxy when Array @trusted_proxies.concat(proxy) else raise ArgumentError, 'Proxy must be a String or Array' end end |
#csp_nonce_enabled? ⇒ Boolean
Check if CSP nonce support is enabled
231 232 233 |
# File 'lib/otto/security/config.rb', line 231 def csp_nonce_enabled? @csp_nonce_enabled end |
#csrf_enabled? ⇒ Boolean
Check if CSRF protection is currently enabled
73 74 75 |
# File 'lib/otto/security/config.rb', line 73 def csrf_enabled? @csrf_protection end |
#debug_csp? ⇒ Boolean
Check if CSP debug logging is enabled
238 239 240 |
# File 'lib/otto/security/config.rb', line 238 def debug_csp? @debug_csp end |
#disable_csp_nonce! ⇒ void
This method returns an undefined value.
Disable CSP nonce support
224 225 226 |
# File 'lib/otto/security/config.rb', line 224 def disable_csp_nonce! @csp_nonce_enabled = false end |
#disable_csrf_protection! ⇒ void
This method returns an undefined value.
Disable CSRF protection
66 67 68 |
# File 'lib/otto/security/config.rb', line 66 def disable_csrf_protection! @csrf_protection = false end |
#enable_csp!(policy = "default-src 'self'") ⇒ void
This method returns an undefined value.
Enable Content Security Policy (CSP) header
CSP helps prevent XSS attacks by controlling which resources can be loaded. The default policy only allows resources from the same origin.
201 202 203 |
# File 'lib/otto/security/config.rb', line 201 def enable_csp!(policy = "default-src 'self'") @security_headers['content-security-policy'] = policy end |
#enable_csp_with_nonce!(debug: false) ⇒ void
This method returns an undefined value.
Enable Content Security Policy (CSP) with nonce support
This enables dynamic CSP header generation with nonces for enhanced security. Unlike enable_csp!, this doesn’t set a static policy but enables the response helper to generate CSP headers with nonces on a per-request basis.
216 217 218 219 |
# File 'lib/otto/security/config.rb', line 216 def enable_csp_with_nonce!(debug: false) @csp_nonce_enabled = true @debug_csp = debug end |
#enable_csrf_protection! ⇒ void
This method returns an undefined value.
Enable CSRF (Cross-Site Request Forgery) protection
When enabled, Otto will:
-
Generate CSRF tokens for safe HTTP methods (GET, HEAD, OPTIONS, TRACE)
-
Validate CSRF tokens for unsafe methods (POST, PUT, DELETE, PATCH)
-
Automatically inject CSRF meta tags into HTML responses
-
Provide helper methods for forms and AJAX requests
59 60 61 |
# File 'lib/otto/security/config.rb', line 59 def enable_csrf_protection! @csrf_protection = true end |
#enable_frame_protection!(option = 'SAMEORIGIN') ⇒ void
This method returns an undefined value.
Enable X-Frame-Options header to prevent clickjacking
256 257 258 |
# File 'lib/otto/security/config.rb', line 256 def enable_frame_protection!(option = 'SAMEORIGIN') @security_headers['x-frame-options'] = option end |
#enable_hsts!(max_age: 31_536_000, include_subdomains: true) ⇒ void
This method returns an undefined value.
Enable HTTP Strict Transport Security (HSTS) header
HSTS forces browsers to use HTTPS for all future requests to this domain. WARNING: This can make your domain inaccessible if HTTPS is not properly configured. Only enable this when you’re certain HTTPS is working correctly.
185 186 187 188 189 |
# File 'lib/otto/security/config.rb', line 185 def enable_hsts!(max_age: 31_536_000, include_subdomains: true) hsts_value = "max-age=#{max_age}" hsts_value += '; includeSubDomains' if include_subdomains @security_headers['strict-transport-security'] = hsts_value end |
#generate_csrf_token(session_id = nil) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/otto/security/config.rb', line 141 def generate_csrf_token(session_id = nil) base = session_id || 'no-session' token = SecureRandom.hex(32) hash_input = base + ':' + token signature = Digest::SHA256.hexdigest(hash_input) csrf_token = "#{token}:#{signature}" puts '=== CSRF Generation ===' puts "hash_input: #{hash_input.inspect}" puts "signature: #{signature}" puts "csrf_token: #{csrf_token}" csrf_token end |
#generate_nonce_csp(nonce, development_mode: false) ⇒ String
Generate a CSP policy string with the provided nonce
247 248 249 250 |
# File 'lib/otto/security/config.rb', line 247 def generate_nonce_csp(nonce, development_mode: false) directives = development_mode ? development_csp_directives(nonce) : production_csp_directives(nonce) directives.join(' ') end |
#get_or_create_session_id(request) ⇒ Object
274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/otto/security/config.rb', line 274 def get_or_create_session_id(request) # Try existing sources first session_id = extract_existing_session_id(request) # Create and persist if none found if session_id.nil? || session_id.empty? session_id = SecureRandom.hex(16) store_session_id(request, session_id) end session_id end |
#set_custom_headers(headers) ⇒ void
This method returns an undefined value.
Set custom security headers
270 271 272 |
# File 'lib/otto/security/config.rb', line 270 def set_custom_headers(headers) @security_headers.merge!(headers) end |
#trusted_proxy?(ip) ⇒ Boolean
Check if an IP address is from a trusted proxy
110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/otto/security/config.rb', line 110 def trusted_proxy?(ip) return false if @trusted_proxies.empty? @trusted_proxies.any? do |proxy| case proxy when String ip == proxy || ip.start_with?(proxy) when Regexp proxy.match?(ip) else false end end end |
#validate_request_size(content_length) ⇒ Boolean
Validate that a request size is within acceptable limits
130 131 132 133 134 135 136 137 138 139 |
# File 'lib/otto/security/config.rb', line 130 def validate_request_size(content_length) return true if content_length.nil? size = content_length.to_i if size > @max_request_size raise Otto::Security::RequestTooLargeError, "Request size #{size} exceeds maximum #{@max_request_size}" end true end |
#verify_csrf_token(token, session_id = nil) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/otto/security/config.rb', line 156 def verify_csrf_token(token, session_id = nil) return false if token.nil? || token.empty? token_part, signature = token.split(':') return false if token_part.nil? || signature.nil? base = session_id || 'no-session' hash_input = "#{base}:#{token_part}" expected_signature = Digest::SHA256.hexdigest(hash_input) comparison_result = secure_compare(signature, expected_signature) puts '=== CSRF Verification ===' puts "hash_input: #{hash_input.inspect}" puts "received_signature: #{signature}" puts "expected_signature: #{expected_signature}" puts "match: #{comparison_result}" comparison_result end |