diff options
author | Andrew White <andrew.white@unboxed.co> | 2018-03-08 14:14:09 +0000 |
---|---|---|
committer | Andrew White <andrew.white@unboxed.co> | 2018-03-08 14:14:09 +0000 |
commit | 190744cd8ed014915803fa805996be04dc750d9d (patch) | |
tree | 66aca1907aac710c55e710f91392f40c49472b1d | |
parent | af406a753c59266c61e9ebcd0f131fdc6533a124 (diff) | |
download | rails-190744cd8ed014915803fa805996be04dc750d9d.tar.gz rails-190744cd8ed014915803fa805996be04dc750d9d.tar.bz2 rails-190744cd8ed014915803fa805996be04dc750d9d.zip |
Always yield a CSP policy instance
If the app has the CSP disabled globally allow a controller action
to enable the policy for that request.
3 files changed, 65 insertions, 17 deletions
diff --git a/actionpack/lib/action_controller/metal/content_security_policy.rb b/actionpack/lib/action_controller/metal/content_security_policy.rb index 67682e7f4f..b8fab4ebe3 100644 --- a/actionpack/lib/action_controller/metal/content_security_policy.rb +++ b/actionpack/lib/action_controller/metal/content_security_policy.rb @@ -17,7 +17,7 @@ module ActionController #:nodoc: def content_security_policy(enabled = true, **options, &block) before_action(options) do if block_given? - policy = request.content_security_policy.clone + policy = current_content_security_policy yield policy request.content_security_policy = policy end @@ -44,5 +44,9 @@ module ActionController #:nodoc: def content_security_policy_nonce request.content_security_policy_nonce end + + def current_content_security_policy + request.content_security_policy.try(:clone) || ActionDispatch::ContentSecurityPolicy.new + end end end diff --git a/actionpack/test/dispatch/content_security_policy_test.rb b/actionpack/test/dispatch/content_security_policy_test.rb index 205bce16d4..f133aae865 100644 --- a/actionpack/test/dispatch/content_security_policy_test.rb +++ b/actionpack/test/dispatch/content_security_policy_test.rb @@ -369,18 +369,6 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest private - def env_config - Rails.application.env_config - end - - def content_security_policy - env_config["action_dispatch.content_security_policy"] - end - - def content_security_policy=(policy) - env_config["action_dispatch.content_security_policy"] = policy - end - def assert_policy(expected, report_only: false) assert_response :success @@ -396,3 +384,61 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest assert_equal expected, response.headers[expected_header] end end + +class DisabledContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest + class PolicyController < ActionController::Base + content_security_policy only: :inline do |p| + p.default_src "https://example.com" + end + + def index + head :ok + end + + def inline + head :ok + end + end + + ROUTES = ActionDispatch::Routing::RouteSet.new + ROUTES.draw do + scope module: "disabled_content_security_policy_integration_test" do + get "/", to: "policy#index" + get "/inline", to: "policy#inline" + end + end + + class PolicyConfigMiddleware + def initialize(app) + @app = app + end + + def call(env) + env["action_dispatch.content_security_policy"] = nil + env["action_dispatch.content_security_policy_nonce_generator"] = nil + env["action_dispatch.content_security_policy_report_only"] = false + env["action_dispatch.show_exceptions"] = false + + @app.call(env) + end + end + + APP = build_app(ROUTES) do |middleware| + middleware.use PolicyConfigMiddleware + middleware.use ActionDispatch::ContentSecurityPolicy::Middleware + end + + def app + APP + end + + def test_generates_no_content_security_policy_by_default + get "/" + assert_nil response.headers["Content-Security-Policy"] + end + + def test_generates_content_security_policy_header_when_globally_disabled + get "/inline" + assert_equal "default-src https://example.com", response.headers["Content-Security-Policy"] + end +end diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb index 39f7791c18..b3fe822218 100644 --- a/railties/lib/rails/application_controller.rb +++ b/railties/lib/rails/application_controller.rb @@ -7,10 +7,8 @@ class Rails::ApplicationController < ActionController::Base # :nodoc: before_action :disable_content_security_policy_nonce! content_security_policy do |policy| - if policy - policy.script_src :unsafe_inline - policy.style_src :unsafe_inline - end + policy.script_src :unsafe_inline + policy.style_src :unsafe_inline end private |