diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb index b1873179..efee3428 100644 --- a/lib/secure_headers/headers/content_security_policy.rb +++ b/lib/secure_headers/headers/content_security_policy.rb @@ -49,15 +49,16 @@ def value # frame-src is deprecated, child-src is being implemented. They are # very similar and in most cases, the same value can be used for both. def normalize_child_frame_src - Kernel.warn("#{Kernel.caller.first}: [DEPRECATION] :frame_src is deprecated, use :child_src instead. Provided: #{@config[:frame_src]}") if @config[:frame_src] + if @config[:frame_src] && @config[:child_src] && @config[:frame_src] != @config[:child_src] + Kernel.warn("#{Kernel.caller.first}: [DEPRECATION] both :child_src and :frame_src supplied and do not match. This can lead to inconsistent behavior across browsers.") + elsif @config[:frame_src] + Kernel.warn("#{Kernel.caller.first}: [DEPRECATION] :frame_src is deprecated, use :child_src instead. Provided: #{@config[:frame_src]}.") + end - child_src = @config[:child_src] || @config[:frame_src] - if child_src - if supported_directives.include?(:child_src) - @config[:child_src] = child_src - else - @config[:frame_src] = child_src - end + if supported_directives.include?(:child_src) + @config[:child_src] = @config[:child_src] || @config[:frame_src] + else + @config[:frame_src] = @config[:frame_src] || @config[:child_src] end end 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 dbbf387a..1e30f62b 100644 --- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb +++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb @@ -86,6 +86,27 @@ module SecureHeaders expect(csp.value).to eq("default-src example.org") end + it "emits a warning when using frame-src" do + expect(Kernel).to receive(:warn).with(/:frame_src is deprecated, use :child_src instead./) + ContentSecurityPolicy.new(default_src: %w('self'), frame_src: %w('self')).value + end + + it "emits a warning when child-src and frame-src are supplied but are not equal" do + expect(Kernel).to receive(:warn).with(/both :child_src and :frame_src supplied and do not match./) + ContentSecurityPolicy.new(default_src: %w('self'), child_src: %w(child-src.com), frame_src: %w(frame-src,com)).value + end + + it "will still set inconsistent child/frame-src values to be less surprising" do + expect(Kernel).to receive(:warn).at_least(:once) + firefox = ContentSecurityPolicy.new({default_src: %w('self'), child_src: %w(child-src.com), frame_src: %w(frame-src,com)}, USER_AGENTS[:firefox]).value + firefox_transitional = ContentSecurityPolicy.new({default_src: %w('self'), child_src: %w(child-src.com), frame_src: %w(frame-src,com)}, USER_AGENTS[:firefox46]).value + expect(firefox).not_to eq(firefox_transitional) + expect(firefox).to match(/frame-src/) + expect(firefox).not_to match(/child-src/) + expect(firefox_transitional).to match(/child-src/) + expect(firefox_transitional).not_to match(/frame-src/) + end + context "browser sniffing" do let (:complex_opts) do (ContentSecurityPolicy::ALL_DIRECTIVES - [:frame_src]).each_with_object({}) do |directive, hash|