Skip to content

Commit

Permalink
handle default csp cases better
Browse files Browse the repository at this point in the history
  • Loading branch information
oreoshake committed Oct 15, 2015
1 parent 37e662f commit 1b20810
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
8 changes: 8 additions & 0 deletions lib/secure_headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class << self

def configure(&block)
self.hpkp = OPT_OUT
self.csp = SecureHeaders::CSP::DEFAULT_CONFIG
instance_eval &block

validate_config!
Expand Down Expand Up @@ -166,6 +167,13 @@ def append_content_security_policy_source(request, additions)
config = secure_headers_request_config(request)[SecureHeaders::CSP::CONFIG_KEY] ||
SecureHeaders::Configuration.fetch(:csp)

# in case we would be appending to an empty directive, fill it with the default-src value
additions.each do |name, addition|
unless config[name]
config[name] = config[:default_src]
end
end

config.merge!(additions) do |_, lhs, rhs|
lhs | rhs
end
Expand Down
3 changes: 2 additions & 1 deletion lib/secure_headers/headers/content_security_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
module SecureHeaders
class ContentSecurityPolicyConfigError < StandardError; end
class ContentSecurityPolicy < Header
DEFAULT_CSP_HEADER = "default-src https:;".freeze
DEFAULT_CSP_HEADER = "default-src https:".freeze
DEFAULT_CONFIG = { default_src: %w(https:)}.freeze
HEADER_NAME = "Content-Security-Policy".freeze
DATA = "data:".freeze
SELF = "'self'".freeze
Expand Down
33 changes: 31 additions & 2 deletions spec/lib/secure_headers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@

def reset_config
SecureHeaders::Configuration.configure do |config|
config.hpkp = SecureHeaders::OPT_OUT
config.hsts = nil
config.x_frame_options = nil
config.x_content_type_options = nil
config.x_xss_protection = nil
config.csp = nil
config.x_download_options = nil
config.x_permitted_cross_domain_policies = nil
end
Expand Down Expand Up @@ -109,6 +107,37 @@ def expect_default_values(hash)
expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline' 'nonce-#{nonce}'")
end

it "appends a value to csp directive" do
SecureHeaders::Configuration.configure do |config|
config.csp = {
:default_src => %w('self'),
:script_src => %w(mycdn.com 'unsafe-inline')
}
end

SecureHeaders::append_content_security_policy_source(@request, script_src: %w(anothercdn.com))
hash = SecureHeaders::header_hash_for(@request)
expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline' anothercdn.com")
end

it "appends the value to the default source when appending to directive without any config" do
SecureHeaders::Configuration.configure do |config|
config.csp = {
:default_src => %w('self')
}
end

SecureHeaders::append_content_security_policy_source(@request, script_src: %w(anothercdn.com))
hash = SecureHeaders::header_hash_for(@request)
expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src 'self'; script-src 'self' anothercdn.com")
end

it "appends a value to the default CSP configuration (for use without a configure block)" do
SecureHeaders::append_content_security_policy_source(@request, script_src: %w(anothercdn.com))
hash = SecureHeaders::header_hash_for(@request)
expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src https:; script-src https: anothercdn.com")
end

it "does not append a nonce when the browser does not support it" do
SecureHeaders::Configuration.configure do |config|
config.csp = {
Expand Down

0 comments on commit 1b20810

Please sign in to comment.