diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index 2c9ef50..566004b 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -133,7 +133,7 @@ module SecureHeaders unless directive == REPORT_URI || @preserve_schemes source_list = strip_source_schemes(source_list) end - dedup_source_list(source_list) + source_list.uniq end end @@ -151,24 +151,6 @@ module SecureHeaders end end - # Removes duplicates and sources that already match an existing wild card. - # - # e.g. *.github.com asdf.github.com becomes *.github.com - def dedup_source_list(sources) - sources = sources.uniq - wild_sources = sources.select { |source| source =~ STAR_REGEXP } - - if wild_sources.any? - schemes = sources.map { |source| [source, URI(source).scheme] }.to_h - sources.reject do |source| - !wild_sources.include?(source) && - wild_sources.any? { |pattern| schemes[pattern] == schemes[source] && File.fnmatch(pattern, source) } - end - else - sources - end - end - # Private: append a nonce to the script/style directories if script_nonce # or style_nonce are provided. def populate_nonces(directive, source_list) diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb index 5639760..314b896 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -48,12 +48,12 @@ module SecureHeaders expect(csp.value).to eq("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:") end - it "minifies source expressions based on overlapping wildcards" do + it "does not minify source expressions based on overlapping wildcards" do config = { default_src: %w(a.example.org b.example.org *.example.org https://*.example.org) } csp = ContentSecurityPolicy.new(config) - expect(csp.value).to eq("default-src *.example.org") + expect(csp.value).to eq("default-src a.example.org b.example.org *.example.org") end it "removes http/s schemes from hosts" do @@ -101,8 +101,13 @@ module SecureHeaders expect(csp.value).to eq("default-src example.org; block-all-mixed-content") end - it "deduplicates any source expressions" do - csp = ContentSecurityPolicy.new(default_src: %w(example.org example.org example.org)) + it "handles wildcard subdomain with wildcard port" do + csp = ContentSecurityPolicy.new(default_src: %w(https://*.example.org:*)) + expect(csp.value).to eq("default-src *.example.org:*") + end + + it "deduplicates source expressions that match exactly (after scheme stripping)" do + csp = ContentSecurityPolicy.new(default_src: %w(example.org https://example.org example.org)) expect(csp.value).to eq("default-src example.org") end