Permalink
Browse files

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.
  • Loading branch information...
pixeltrix committed Mar 8, 2018
1 parent 619b1b6 commit 4ec8bf68ff92f35e79232fbd605012ce1f4e1e6e
@@ -1,3 +1,10 @@
* Always yield a CSP policy instance from `content_security_policy`
This allows a controller action to enable the policy individually
for a controller and/or specific actions.
*Andrew White*
* Add the ability to disable the global CSP in a controller, e.g:
class LegacyPagesController < ApplicationController
@@ -17,7 +17,7 @@ module ClassMethods
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 @@ def content_security_policy?
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
@@ -369,18 +369,6 @@ def test_generates_no_content_security_policy
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 @@ def assert_policy(expected, report_only: false)
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
@@ -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

0 comments on commit 4ec8bf6

Please sign in to comment.