CrackedRuby CrackedRuby

Overview

Security headers are HTTP response headers sent by web servers to control how browsers handle content, execute scripts, load resources, and interact with web applications. These headers form a critical layer of defense-in-depth security strategy by instructing browsers to enforce specific security policies regardless of the application code.

Modern browsers support a range of security headers designed to prevent attacks such as cross-site scripting (XSS), clickjacking, man-in-the-middle attacks, and data injection. Each header addresses a specific vulnerability class by restricting browser behavior in ways that block common attack vectors. While application-level security remains essential, security headers provide an additional enforcement mechanism that operates at the browser level.

The effectiveness of security headers depends on proper configuration. Misconfigured headers can break application functionality, while missing headers leave applications vulnerable to preventable attacks. Security headers apply across all modern browsers, though implementation details and support vary by browser version.

# Basic security header response
HTTP/1.1 200 OK
Content-Type: text/html
Content-Security-Policy: default-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000

Security headers have evolved from simple directives like X-Frame-Options to complex policy systems like Content Security Policy (CSP) that support granular control over resource loading and script execution. This evolution reflects the growing sophistication of web-based attacks and the need for more precise security controls.

Key Principles

Security headers operate on a principle of explicit permission rather than implicit trust. By default, browsers allow broad behavior including executing inline scripts, loading resources from any origin, and embedding content in frames. Security headers reverse this model by requiring explicit declaration of permitted actions.

The Content Security Policy (CSP) header defines allowed sources for scripts, styles, images, fonts, and other resources. CSP works by establishing a whitelist of trusted sources and blocking any content that doesn't match. This prevents XSS attacks where malicious scripts are injected into pages, as the injected scripts won't match the CSP whitelist and the browser will refuse to execute them.

# CSP blocks unauthorized scripts
Content-Security-Policy: script-src 'self' https://trusted-cdn.com

# Inline script blocked - doesn't match policy
<script>maliciousCode()</script>

# External script from trusted source - allowed
<script src="https://trusted-cdn.com/app.js"></script>

The Strict-Transport-Security (HSTS) header enforces HTTPS connections by instructing browsers to only connect via secure protocols. Once a browser receives an HSTS header, it automatically upgrades all subsequent requests to HTTPS and refuses to connect over plain HTTP. This prevents man-in-the-middle attacks that exploit the initial HTTP request before redirection to HTTPS.

Frame control headers prevent clickjacking attacks where malicious sites embed target pages in iframes and trick users into performing unintended actions. The X-Frame-Options header controls whether a page can be displayed in a frame, with options to deny framing entirely, allow only same-origin framing, or specify allowed domains.

# Prevent all framing
X-Frame-Options: DENY

# Allow only same-origin framing
X-Frame-Options: SAMEORIGIN

# Allow specific domain
X-Frame-Options: ALLOW-FROM https://trusted.example.com

The X-Content-Type-Options header prevents MIME type sniffing where browsers attempt to determine content types by inspecting file contents rather than trusting the declared Content-Type header. Setting this to nosniff forces browsers to respect declared content types, preventing scenarios where user-uploaded files are executed as scripts.

Referrer control headers manage what information browsers send in the Referer header when navigating between pages. The Referrer-Policy header controls whether full URLs, origins only, or no referrer information is sent, preventing information leakage through URLs that may contain sensitive parameters.

Permissions Policy (formerly Feature Policy) controls access to browser features like geolocation, camera, microphone, and payment APIs. This header prevents malicious scripts or third-party content from accessing powerful browser features without explicit permission.

Security Implications

Security headers create multiple defense layers that protect against different attack vectors. The primary security benefit comes from reducing the attack surface by restricting what browsers can do with content served by the application.

Cross-site scripting attacks inject malicious scripts into web pages viewed by other users. Without CSP, browsers execute any script found in page content, including attacker-injected scripts. A properly configured CSP prevents XSS by blocking inline scripts and restricting script sources to trusted domains. Even if an attacker successfully injects script tags into page content, the browser refuses to execute them.

# CSP configuration that blocks XSS
Content-Security-Policy: default-src 'self'; 
                         script-src 'self' https://trusted-scripts.com;
                         style-src 'self' 'unsafe-inline';
                         img-src 'self' data: https:;
                         font-src 'self' https://trusted-fonts.com;
                         connect-src 'self' https://api.example.com;
                         frame-ancestors 'none';

Man-in-the-middle attacks intercept traffic between browsers and servers to steal credentials or inject malicious content. HSTS prevents these attacks by ensuring browsers only connect via HTTPS after the first successful connection. The includeSubDomains directive extends protection to all subdomains, and preload allows browsers to enforce HTTPS before the first connection by including the domain in browser preload lists.

Clickjacking tricks users into clicking elements on a hidden page overlaid on a visible page. Frame control headers prevent this by blocking the page from being embedded in frames. The Content Security Policy frame-ancestors directive provides more granular control than X-Frame-Options, allowing specification of multiple allowed origins.

MIME sniffing attacks upload files with misleading content types that browsers then execute as scripts. Setting X-Content-Type-Options: nosniff forces browsers to respect declared content types, preventing uploaded images from being executed as HTML or JavaScript.

# Prevent MIME sniffing on file uploads
def serve_upload
  send_file uploaded_file.path,
    type: uploaded_file.content_type,
    disposition: 'attachment',
    headers: {
      'X-Content-Type-Options' => 'nosniff',
      'Content-Security-Policy' => "default-src 'none'"
    }
end

Cross-origin attacks exploit browser same-origin policy weaknesses to access data from other domains. CORS headers control cross-origin access, but security headers like CSP add additional restrictions on what resources can be loaded from which origins.

Information leakage through referrer headers exposes sensitive URL parameters and application structure to third parties. Configuring Referrer-Policy to strict-origin-when-cross-origin or no-referrer prevents leaking sensitive information while maintaining analytics capabilities.

Permission abuse occurs when malicious scripts or third-party content access browser features like camera, microphone, or geolocation without user consent. Permissions Policy restricts these capabilities to trusted contexts, preventing unauthorized access to sensitive device features.

Ruby Implementation

Rails applications implement security headers through middleware, controller actions, or application configuration. The secure_headers gem provides a comprehensive solution for managing security headers with sensible defaults and configuration options.

# Gemfile
gem 'secure_headers'

# config/initializers/secure_headers.rb
SecureHeaders::Configuration.default do |config|
  config.csp = {
    default_src: %w['self'],
    script_src: %w['self' https://trusted-cdn.com],
    style_src: %w['self' 'unsafe-inline'],
    img_src: %w['self' data: https:],
    font_src: %w['self' https://fonts.gstatic.com],
    connect_src: %w['self' https://api.example.com],
    frame_ancestors: %w['none'],
    base_uri: %w['self'],
    form_action: %w['self']
  }
  
  config.hsts = "max-age=#{1.year.to_i}; includeSubDomains; preload"
  config.x_frame_options = "DENY"
  config.x_content_type_options = "nosniff"
  config.x_xss_protection = "0"  # Disabled in modern browsers
  config.referrer_policy = "strict-origin-when-cross-origin"
end

The secure_headers gem automatically applies configured headers to all responses. Per-controller or per-action customization uses the override_content_security_policy_directives method when specific pages require different policies.

class DashboardController < ApplicationController
  # Allow inline scripts for this controller
  content_security_policy do |policy|
    policy.script_src :self, :unsafe_inline
  end
  
  def analytics_dashboard
    # Additional directives for this action
    append_content_security_policy_directives(
      script_src: %w[https://analytics-provider.com],
      connect_src: %w[https://analytics-api.com]
    )
  end
end

Rails 5.2+ includes built-in CSP configuration through application configuration and controller DSL. This provides CSP support without additional gems for applications with simpler requirements.

# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.font_src    :self, :https, :data
  policy.img_src     :self, :https, :data
  policy.object_src  :none
  policy.script_src  :self, :https
  policy.style_src   :self, :https
  
  # Generate nonce for inline scripts
  policy.script_src :self, :https, :unsafe_inline unless Rails.env.production?
end

# Enable nonce generation
Rails.application.config.content_security_policy_nonce_generator = 
  ->(request) { SecureRandom.base64(16) }

# Report violations
Rails.application.config.content_security_policy_report_only = false

Rack middleware provides security headers for non-Rails applications or when middleware-based configuration is preferred. Custom middleware applies headers to all responses with flexible configuration options.

# config.ru
require 'rack'

class SecurityHeaders
  def initialize(app)
    @app = app
  end
  
  def call(env)
    status, headers, body = @app.call(env)
    
    headers['Content-Security-Policy'] = csp_policy
    headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    headers['X-Frame-Options'] = 'SAMEORIGIN'
    headers['X-Content-Type-Options'] = 'nosniff'
    headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    
    [status, headers, body]
  end
  
  private
  
  def csp_policy
    directives = {
      'default-src' => ["'self'"],
      'script-src' => ["'self'", 'https://trusted-cdn.com'],
      'style-src' => ["'self'", "'unsafe-inline'"],
      'img-src' => ["'self'", 'data:', 'https:']
    }
    
    directives.map { |k, v| "#{k} #{v.join(' ')}" }.join('; ')
  end
end

use SecurityHeaders
run YourApp

Sinatra applications configure security headers through helpers or before filters that set headers on each request.

require 'sinatra'

helpers do
  def set_security_headers
    headers 'Content-Security-Policy' => "default-src 'self'",
            'X-Frame-Options' => 'DENY',
            'X-Content-Type-Options' => 'nosniff',
            'Strict-Transport-Security' => 'max-age=31536000',
            'Referrer-Policy' => 'no-referrer'
  end
end

before do
  set_security_headers
end

get '/' do
  erb :index
end

CSP nonces provide a mechanism for allowing specific inline scripts while blocking others. Rails generates unique nonces per request and automatically injects them into script tags when using javascript_tag with the nonce: true option.

# View template
<%= javascript_tag nonce: true do %>
  // This inline script allowed via nonce
  console.log('Trusted inline script');
<% end %>

# Generated HTML includes nonce attribute
<script nonce="random-base64-value">
  console.log('Trusted inline script');
</script>

# CSP header includes nonce
Content-Security-Policy: script-src 'self' 'nonce-random-base64-value'

Practical Examples

A public-facing marketing site requires strict security while allowing analytics and embedded videos. The configuration blocks unauthorized scripts while permitting trusted third-party resources.

# config/initializers/secure_headers.rb
SecureHeaders::Configuration.default do |config|
  config.csp = {
    default_src: %w['none'],
    script_src: %w[
      'self'
      https://www.google-analytics.com
      https://www.googletagmanager.com
    ],
    style_src: %w['self' 'unsafe-inline'],
    img_src: %w['self' https: data:],
    font_src: %w['self' https://fonts.gstatic.com],
    connect_src: %w['self' https://www.google-analytics.com],
    frame_src: %w[https://www.youtube.com https://player.vimeo.com],
    frame_ancestors: %w['none'],
    base_uri: %w['self'],
    form_action: %w['self']
  }
  
  config.hsts = "max-age=#{2.years.to_i}; includeSubDomains; preload"
  config.x_frame_options = "DENY"
  config.x_content_type_options = "nosniff"
  config.referrer_policy = "strict-origin-when-cross-origin"
  
  # Report CSP violations for monitoring
  config.csp_report_only = Rails.env.production? ? false : true
  config.report_uri = %w[https://csp-reporting.example.com/report]
end

A SaaS application dashboard with user-generated content requires strict CSP to prevent XSS while allowing necessary functionality. Different sections of the application need different policies based on their security requirements.

class ApplicationController < ActionController::Base
  # Base security policy for all pages
  content_security_policy do |policy|
    policy.default_src :self
    policy.script_src :self
    policy.style_src :self, :unsafe_inline  # Required for some UI frameworks
    policy.img_src :self, :https, :data
    policy.connect_src :self, 'https://api.example.com'
    policy.frame_ancestors :none
  end
end

class UserContentController < ApplicationController
  # Stricter policy for user-generated content
  content_security_policy do |policy|
    policy.default_src :none
    policy.img_src :self, :data
    policy.style_src :self
    policy.sandbox 'allow-same-origin'
  end
  
  def show
    @content = UserContent.find(params[:id])
    
    # Additional CSP for this specific content
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-Content-Type-Options'] = 'nosniff'
  end
end

class AdminController < ApplicationController
  # Admin interface needs additional resources
  content_security_policy do |policy|
    policy.script_src :self, 'https://admin-tools.example.com'
    policy.connect_src :self, 'https://api.example.com', 'wss://realtime.example.com'
  end
end

An API-only Rails application requires different security header configuration since it doesn't serve HTML content but still needs protection against certain attacks.

# config/initializers/api_security_headers.rb
Rails.application.config.middleware.use(
  Rack::Attack
)

class ApiSecurityHeaders
  def initialize(app)
    @app = app
  end
  
  def call(env)
    status, headers, body = @app.call(env)
    
    # HSTS still important for API endpoints
    headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    
    # Prevent MIME sniffing on API responses
    headers['X-Content-Type-Options'] = 'nosniff'
    
    # No framing needed for API
    headers['X-Frame-Options'] = 'DENY'
    
    # Prevent caching sensitive API responses
    headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, private'
    headers['Pragma'] = 'no-cache'
    
    # API-specific CSP - no scripts needed
    headers['Content-Security-Policy'] = "default-src 'none'; frame-ancestors 'none'"
    
    [status, headers, body]
  end
end

Rails.application.config.middleware.use ApiSecurityHeaders

A file upload service requires careful header configuration to prevent uploaded files from being executed as scripts or embedding the application in frames.

class UploadsController < ApplicationController
  def show
    @upload = Upload.find(params[:id])
    
    send_file @upload.file_path,
      type: @upload.content_type,
      disposition: 'inline',
      headers: {
        # Prevent MIME sniffing
        'X-Content-Type-Options' => 'nosniff',
        
        # Prevent embedding uploaded content
        'X-Frame-Options' => 'DENY',
        
        # Strict CSP for uploaded content
        'Content-Security-Policy' => "default-src 'none'; style-src 'unsafe-inline'; sandbox",
        
        # Prevent caching user uploads
        'Cache-Control' => 'private, no-cache, no-store, must-revalidate'
      }
  end
  
  def download
    @upload = Upload.find(params[:id])
    
    send_file @upload.file_path,
      type: @upload.content_type,
      disposition: 'attachment',  # Force download
      filename: @upload.sanitized_filename,
      headers: {
        'X-Content-Type-Options' => 'nosniff',
        'Content-Security-Policy' => "default-src 'none'; sandbox"
      }
  end
end

Common Pitfalls

The 'unsafe-inline' directive in CSP defeats the primary protection mechanism against XSS attacks. Many developers add this directive when inline scripts break, but this allows all inline scripts including injected malicious code. Use nonces or hashes instead to allow specific inline scripts.

# Incorrect - allows all inline scripts
Content-Security-Policy: script-src 'self' 'unsafe-inline'

# Correct - use nonces for specific inline scripts
Content-Security-Policy: script-src 'self' 'nonce-abc123'

# Or use script hashes
Content-Security-Policy: script-src 'self' 'sha256-hash-of-script'

The 'unsafe-eval' directive allows eval() and related functions that can execute strings as code. This undermines CSP protection and should be avoided. Most modern frameworks and libraries don't require eval(), and those that do can often be replaced with safer alternatives.

Missing the includeSubDomains directive in HSTS leaves subdomains vulnerable to downgrade attacks. An attacker can intercept traffic to subdomains that don't enforce HTTPS and use that as a pivot to compromise the main domain.

# Incomplete - subdomains not protected
Strict-Transport-Security: max-age=31536000

# Complete - all subdomains protected
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Setting HSTS with a short max-age value reduces protection effectiveness. Browsers only enforce HSTS for the duration specified in max-age. Using values less than one year means browsers may connect via HTTP if they haven't visited the site recently. Production applications should use one to two years.

The X-Frame-Options header conflicts with CSP frame-ancestors directive. When both are present, browsers prioritize CSP and ignore X-Frame-Options. Set either one or both for compatibility with older browsers, but ensure they don't contradict each other.

# Contradictory - CSP allows framing but X-Frame-Options denies
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'self'

# Consistent - both deny framing
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'

Forgetting to set security headers in development and staging environments means violations are not discovered until production. Use report-only mode in non-production environments to identify issues without breaking functionality.

# Development environment
config.content_security_policy_report_only = true
config.content_security_policy_nonce_generator = ->(request) { SecureRandom.base64(16) }

# Production environment
config.content_security_policy_report_only = false

Overly permissive CSP policies using wildcards undermine security benefits. Directives like script-src https: allow scripts from any HTTPS source, which provides minimal protection against XSS.

# Too permissive - allows any HTTPS script
Content-Security-Policy: script-src https:

# Better - specific trusted domains
Content-Security-Policy: script-src 'self' https://trusted-cdn.com https://analytics.google.com

Not handling CSP violations means security issues go unnoticed. Configure CSP reporting to collect violation reports and monitor them regularly to identify attack attempts or configuration problems.

# Configure CSP reporting
config.csp = {
  default_src: %w['self'],
  script_src: %w['self'],
  report_uri: %w[/csp-violation-report-endpoint]
}

# Controller to handle reports
class CspReportsController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def create
    violation = JSON.parse(request.body.read)
    
    Rails.logger.warn "CSP Violation: #{violation['csp-report']}"
    
    # Store in database or send to monitoring service
    CspViolation.create!(
      document_uri: violation.dig('csp-report', 'document-uri'),
      violated_directive: violation.dig('csp-report', 'violated-directive'),
      blocked_uri: violation.dig('csp-report', 'blocked-uri'),
      original_policy: violation.dig('csp-report', 'original-policy')
    )
    
    head :ok
  end
end

Setting Referrer-Policy to no-referrer breaks analytics and breaks same-site navigation tracking. Use strict-origin-when-cross-origin to send origin information for cross-origin requests while sending full URLs for same-origin navigation.

Caching responses with security headers can cause stale policies to be served. Use appropriate cache control headers alongside security headers, especially for CSP configurations that may need updates.

Testing Approaches

Automated testing validates security header configuration to catch misconfigurations before deployment. Integration tests verify headers are present with correct values across different controllers and actions.

# spec/requests/security_headers_spec.rb
RSpec.describe "Security Headers", type: :request do
  describe "GET /" do
    before { get root_path }
    
    it "sets Content-Security-Policy" do
      expect(response.headers['Content-Security-Policy']).to include("default-src 'self'")
    end
    
    it "sets Strict-Transport-Security" do
      hsts = response.headers['Strict-Transport-Security']
      expect(hsts).to match(/max-age=\d+/)
      expect(hsts).to include('includeSubDomains')
    end
    
    it "sets X-Frame-Options" do
      expect(response.headers['X-Frame-Options']).to eq('DENY')
    end
    
    it "sets X-Content-Type-Options" do
      expect(response.headers['X-Content-Type-Options']).to eq('nosniff')
    end
    
    it "sets Referrer-Policy" do
      expect(response.headers['Referrer-Policy']).to eq('strict-origin-when-cross-origin')
    end
  end
  
  describe "CSP nonce generation" do
    it "generates unique nonces per request" do
      get root_path
      first_nonce = response.headers['Content-Security-Policy'][/nonce-([^']+)/, 1]
      
      get root_path
      second_nonce = response.headers['Content-Security-Policy'][/nonce-([^']+)/, 1]
      
      expect(first_nonce).not_to eq(second_nonce)
    end
  end
end

Controller-specific tests verify that per-action CSP configurations apply correctly and don't conflict with global settings.

RSpec.describe DashboardController, type: :controller do
  describe "GET #analytics" do
    it "includes analytics script source in CSP" do
      get :analytics
      
      csp = response.headers['Content-Security-Policy']
      expect(csp).to include('https://analytics-provider.com')
    end
  end
  
  describe "GET #user_content" do
    it "applies strict CSP for user content" do
      get :user_content, params: { id: 1 }
      
      csp = response.headers['Content-Security-Policy']
      expect(csp).to include("default-src 'none'")
      expect(csp).to include('sandbox')
    end
  end
end

Browser testing with tools like Selenium or Capybara verifies that CSP doesn't break application functionality while still providing protection.

# spec/system/security_spec.rb
RSpec.describe "Security policies", type: :system do
  it "allows trusted scripts to execute" do
    visit root_path
    
    # Trusted script should execute
    expect(page).to have_css('.js-initialized')
  end
  
  it "blocks inline scripts without nonces" do
    visit page_with_inline_script_path
    
    # Check console for CSP violations
    logs = page.driver.browser.manage.logs.get(:browser)
    csp_violations = logs.select { |log| log.message.include?('Content Security Policy') }
    
    expect(csp_violations).to be_present
  end
end

Manual testing with browser developer tools confirms proper header configuration and identifies CSP violations. Browser console displays CSP violations with details about the blocked resource and violated directive.

Security scanning tools automate header verification across multiple pages. Tools like Security Headers, Mozilla Observatory, or custom scripts check for missing or misconfigured headers.

# lib/tasks/security_audit.rake
namespace :security do
  desc "Audit security headers across key pages"
  task audit: :environment do
    require 'net/http'
    require 'uri'
    
    pages = [
      '/',
      '/login',
      '/dashboard',
      '/api/v1/users'
    ]
    
    results = pages.map do |path|
      uri = URI.parse("https://#{ENV['APP_DOMAIN']}#{path}")
      response = Net::HTTP.get_response(uri)
      
      {
        path: path,
        csp: response['Content-Security-Policy'],
        hsts: response['Strict-Transport-Security'],
        x_frame: response['X-Frame-Options'],
        x_content_type: response['X-Content-Type-Options']
      }
    end
    
    results.each do |result|
      puts "\n#{result[:path]}"
      result.except(:path).each do |header, value|
        status = value.present? ? '' : ''
        puts "  #{status} #{header}: #{value || 'MISSING'}"
      end
    end
  end
end

CSP violation reporting in production provides ongoing monitoring of security policy effectiveness. Configure a reporting endpoint and analyze violations to identify attack attempts or legitimate functionality blocked by overly strict policies.

# app/controllers/csp_reports_controller.rb
class CspReportsController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def create
    violation = parse_violation(request.body.read)
    
    if legitimate_violation?(violation)
      notify_security_team(violation)
      store_violation(violation)
    end
    
    head :ok
  end
  
  private
  
  def parse_violation(body)
    JSON.parse(body)['csp-report']
  rescue JSON::ParserError
    nil
  end
  
  def legitimate_violation?(violation)
    return false unless violation
    
    # Filter out browser extensions and known false positives
    blocked_uri = violation['blocked-uri']
    return false if blocked_uri.start_with?('chrome-extension://', 'moz-extension://')
    
    true
  end
  
  def store_violation(violation)
    CspViolationLog.create!(
      document_uri: violation['document-uri'],
      violated_directive: violation['violated-directive'],
      blocked_uri: violation['blocked-uri'],
      source_file: violation['source-file'],
      line_number: violation['line-number']
    )
  end
  
  def notify_security_team(violation)
    SecurityMailer.csp_violation(violation).deliver_later
  end
end

Reference

Core Security Headers

Header Purpose Common Values
Content-Security-Policy Controls resource loading and script execution default-src 'self'; script-src 'self' https://trusted.com
Strict-Transport-Security Enforces HTTPS connections max-age=31536000; includeSubDomains; preload
X-Frame-Options Controls page framing DENY, SAMEORIGIN, ALLOW-FROM uri
X-Content-Type-Options Prevents MIME sniffing nosniff
Referrer-Policy Controls referrer information no-referrer, strict-origin-when-cross-origin
Permissions-Policy Controls browser feature access geolocation=(), camera=(), microphone=()

CSP Directives

Directive Controls Example
default-src Default source for all resource types default-src 'self'
script-src JavaScript sources script-src 'self' https://cdn.example.com
style-src CSS sources style-src 'self' 'unsafe-inline'
img-src Image sources img-src 'self' data: https:
font-src Font sources font-src 'self' https://fonts.gstatic.com
connect-src XMLHttpRequest, WebSocket, EventSource connect-src 'self' https://api.example.com
frame-src iframe sources frame-src https://www.youtube.com
frame-ancestors Who can embed this page frame-ancestors 'none'
base-uri Base element URLs base-uri 'self'
form-action Form submission targets form-action 'self'
object-src Plugin sources object-src 'none'
media-src Audio and video sources media-src 'self' https://media.example.com

CSP Source Values

Value Meaning Use Case
'none' Block all sources Disable resource type completely
'self' Same origin only Allow resources from same domain
'unsafe-inline' Allow inline scripts/styles Avoid in production if possible
'unsafe-eval' Allow eval and similar functions Avoid - security risk
https: Any HTTPS source Too permissive for scripts
data: Data URIs Useful for inline images
'nonce-value' Script with matching nonce Allow specific inline scripts
'sha256-hash' Resource with matching hash Allow specific inline content
domain.com Specific domain Trusted third-party resources

HSTS Configuration

Parameter Purpose Recommended Value
max-age Duration in seconds 31536000 (1 year) or 63072000 (2 years)
includeSubDomains Apply to all subdomains Include for comprehensive protection
preload Submit to browser preload lists Include after testing thoroughly

Referrer Policy Values

Value Behavior Use Case
no-referrer Never send referrer Maximum privacy
no-referrer-when-downgrade Send for HTTPS to HTTPS Default in most browsers
origin Send origin only Balance privacy and functionality
origin-when-cross-origin Full URL for same-origin Good balance
same-origin Send for same-origin only Strict internal tracking
strict-origin Origin for HTTPS to HTTPS Good for most sites
strict-origin-when-cross-origin Combines strict-origin and origin-when-cross-origin Recommended default
unsafe-url Always send full URL Avoid - leaks sensitive data

Rails Configuration Methods

Method Purpose Example
content_security_policy Set CSP directives policy.script_src :self, :https
append_content_security_policy_directives Add to existing policy append_content_security_policy_directives script_src: ['https://new.com']
override_content_security_policy_directives Replace directives override_content_security_policy_directives script_src: [:self]
content_security_policy_nonce_generator Generate nonces ->(request) { SecureRandom.base64(16) }
content_security_policy_report_only Report mode true for testing, false for enforcement

Common CSP Patterns

Pattern Configuration Use Case
Strict CSP default-src 'none'; script-src 'nonce-{random}' Maximum security
API responses default-src 'none'; frame-ancestors 'none' JSON APIs
Static content default-src 'self'; img-src 'self' https: data: Simple sites
Third-party analytics script-src 'self' https://analytics.com; connect-src https://api.analytics.com Marketing sites
User content default-src 'none'; sandbox User uploads
Development mode script-src 'self' 'unsafe-inline' 'unsafe-eval' Local development only