Merge pull request #14 from twitter/whitelist_data_img_src
Append data: to the img-src directive automatically
This commit is contained in:
Коммит
706db74ff2
2
Gemfile
2
Gemfile
|
@ -8,4 +8,6 @@ group :test do
|
||||||
gem 'growl'
|
gem 'growl'
|
||||||
gem 'rb-fsevent'
|
gem 'rb-fsevent'
|
||||||
gem 'simplecov'
|
gem 'simplecov'
|
||||||
|
gem 'debugger', :platform => :ruby_19
|
||||||
|
gem 'ruby-debug', :platform => :ruby_18
|
||||||
end
|
end
|
||||||
|
|
|
@ -263,6 +263,12 @@ module SecureHeaders
|
||||||
|
|
||||||
def generic_directives(config)
|
def generic_directives(config)
|
||||||
header_value = ''
|
header_value = ''
|
||||||
|
if config[:img_src]
|
||||||
|
config[:img_src] = config[:img_src] + ['data:'] unless config[:img_src].include?('data:')
|
||||||
|
else
|
||||||
|
config[:img_src] = ['data:']
|
||||||
|
end
|
||||||
|
|
||||||
config.keys.sort_by{|k| k.to_s}.each do |k| # ensure consistent ordering
|
config.keys.sort_by{|k| k.to_s}.each do |k| # ensure consistent ordering
|
||||||
header_value += "#{symbol_to_hyphen_case(k)} #{config[k].join(" ")}; "
|
header_value += "#{symbol_to_hyphen_case(k)} #{config[k].join(" ")}; "
|
||||||
end
|
end
|
||||||
|
|
|
@ -232,23 +232,35 @@ module SecureHeaders
|
||||||
}.should raise_error(ContentSecurityPolicyBuildError, "Couldn't build CSP header :( Expected to find default_src directive value")
|
}.should raise_error(ContentSecurityPolicyBuildError, "Couldn't build CSP header :( Expected to find default_src directive value")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "auto-whitelists data: uris for img-src" do
|
||||||
|
|
||||||
|
it "sets the value if no img-src specified" do
|
||||||
|
csp = ContentSecurityPolicy.new(request_for(CHROME), {:default_src => 'self', :disable_fill_missing => true, :disable_chrome_extension => true})
|
||||||
|
csp.value.should == "default-src 'self'; img-src data:;"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "appends the value if img-src is specified" do
|
||||||
|
csp = ContentSecurityPolicy.new(request_for(CHROME), {:default_src => 'self', :img_src => 'self', :disable_fill_missing => true, :disable_chrome_extension => true})
|
||||||
|
csp.value.should == "default-src 'self'; img-src 'self' data:;"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "fills in directives without values with default-src value" do
|
it "fills in directives without values with default-src value" do
|
||||||
options = default_opts.merge(:disable_fill_missing => false)
|
options = default_opts.merge(:disable_fill_missing => false)
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME), options)
|
csp = ContentSecurityPolicy.new(request_for(CHROME), options)
|
||||||
default = "default-src https://*;"
|
value = "default-src https://*; connect-src https://*; font-src https://*; frame-src https://*; img-src https://* data:; media-src https://*; object-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
||||||
value = "default-src https://*; connect-src https://*; font-src https://*; frame-src https://*; img-src https://*; media-src https://*; object-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
|
||||||
csp.value.should == value
|
csp.value.should == value
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends the chrome csp header if an unknown browser is supplied" do
|
it "sends the chrome csp header if an unknown browser is supplied" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(IE), default_opts)
|
csp = ContentSecurityPolicy.new(request_for(IE), default_opts)
|
||||||
csp.value.should == "default-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should match "default-src"
|
||||||
end
|
end
|
||||||
|
|
||||||
context "X-Content-Security-Policy" do
|
context "X-Content-Security-Policy" do
|
||||||
it "builds a csp header for firefox" do
|
it "builds a csp header for firefox" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX), default_opts)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX), default_opts)
|
||||||
csp.value.should == "allow https://*; options inline-script eval-script; script-src https://* data:; style-src https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should == "allow https://*; options inline-script eval-script; img-src data:; script-src https://* data:; style-src https://* chrome-extension: about:; report-uri /csp_report;"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "copies connect-src values to xhr_src values" do
|
it "copies connect-src values to xhr_src values" do
|
||||||
|
@ -259,7 +271,7 @@ module SecureHeaders
|
||||||
:disable_fill_missing => true
|
:disable_fill_missing => true
|
||||||
}
|
}
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX), opts)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX), opts)
|
||||||
csp.value.should == "allow http://twitter.com; xhr-src 'self' http://*.localhost.com:*;"
|
csp.value.should =~ /xhr-src 'self' http:/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "copies connect-src values to xhr_src values for FF 18" do
|
it "copies connect-src values to xhr_src values for FF 18" do
|
||||||
|
@ -270,35 +282,34 @@ module SecureHeaders
|
||||||
:disable_fill_missing => true
|
:disable_fill_missing => true
|
||||||
}
|
}
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX_18), opts)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX_18), opts)
|
||||||
csp.value.should == "default-src http://twitter.com; xhr-src 'self' http://*.localhost.com:*;"
|
csp.value.should =~ /xhr-src 'self' http:\/\/\*\.localhost\.com:\*/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "builds a w3c-style-ish header for Firefox > version 18" do
|
it "builds a w3c-style-ish header for Firefox > version 18" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX_18), default_opts)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX_18), default_opts)
|
||||||
csp.value.should == "default-src https://*; options inline-script eval-script; script-src https://* data:; style-src https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should =~ /default-src/
|
||||||
end
|
end
|
||||||
|
|
||||||
# cross-host posting not allowed in FF < 18
|
# cross-host posting not allowed in FF < 18
|
||||||
it "changes the report-uri to the local forwarder path if cross-host" do
|
it "changes the report-uri to the local forwarder path if cross-host" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX), @options_with_forwarding)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX), @options_with_forwarding)
|
||||||
csp.value.should == "allow https://*; options inline-script eval-script; script-src https://* data:; style-src https://* chrome-extension: about:; report-uri #{@options_with_forwarding[:forward_endpoint]};"
|
csp.value.should =~ /report-uri #{@options_with_forwarding[:forward_endpoint]};/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "X-Webkit-CSP" do
|
context "X-Webkit-CSP" do
|
||||||
it "builds a csp header for chrome" do
|
it "builds a csp header for chrome" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME), default_opts)
|
csp = ContentSecurityPolicy.new(request_for(CHROME), default_opts)
|
||||||
csp.value.should == "default-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should == "default-src https://*; img-src data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ignores :forward_endpoint settings" do
|
it "ignores :forward_endpoint settings" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME), @options_with_forwarding)
|
csp = ContentSecurityPolicy.new(request_for(CHROME), @options_with_forwarding)
|
||||||
csp.value.should == "default-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri #{@options_with_forwarding[:report_uri]};"
|
csp.value.should =~ /report-uri #{@options_with_forwarding[:report_uri]};/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "whitelists chrome_extensions by default" do
|
it "whitelists chrome_extensions by default" do
|
||||||
opts = {
|
opts = {
|
||||||
:disable_fill_missing => true,
|
|
||||||
:default_src => 'https://*',
|
:default_src => 'https://*',
|
||||||
:report_uri => '/csp_report',
|
:report_uri => '/csp_report',
|
||||||
:script_src => 'inline eval https://* data:',
|
:script_src => 'inline eval https://* data:',
|
||||||
|
@ -306,7 +317,9 @@ module SecureHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME), opts)
|
csp = ContentSecurityPolicy.new(request_for(CHROME), opts)
|
||||||
csp.value.should == "default-src https://* chrome-extension:; script-src 'unsafe-inline' 'unsafe-eval' https://* data: chrome-extension:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
|
||||||
|
# ignore the report-uri directive
|
||||||
|
csp.value.split(';')[0...-1].each{|directive| directive.should =~ /chrome-extension:/}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -324,12 +337,12 @@ module SecureHeaders
|
||||||
let(:header) {}
|
let(:header) {}
|
||||||
it "returns the original value" do
|
it "returns the original value" do
|
||||||
header = ContentSecurityPolicy.new(request_for(CHROME), options)
|
header = ContentSecurityPolicy.new(request_for(CHROME), options)
|
||||||
header.value.should == "default-src 'self'; script-src https://*;"
|
header.value.should == "default-src 'self'; img-src data:; script-src https://*;"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "it returns the experimental value if requested" do
|
it "it returns the experimental value if requested" do
|
||||||
header = ContentSecurityPolicy.new(request_for(CHROME), options, :experimental => true)
|
header = ContentSecurityPolicy.new(request_for(CHROME), options, :experimental => true)
|
||||||
header.value.should == "default-src 'self'; script-src 'self';"
|
header.value.should_not =~ /https/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -345,12 +358,12 @@ module SecureHeaders
|
||||||
|
|
||||||
it "adds directive values for headers on http" do
|
it "adds directive values for headers on http" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME), options)
|
csp = ContentSecurityPolicy.new(request_for(CHROME), options)
|
||||||
csp.value.should == "default-src https://*; frame-src http://*; img-src http://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should == "default-src https://*; frame-src http://*; img-src http://* data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not add the directive values if requesting https" do
|
it "does not add the directive values if requesting https" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(CHROME, '/', :ssl => true), options)
|
csp = ContentSecurityPolicy.new(request_for(CHROME, '/', :ssl => true), options)
|
||||||
csp.value.should == "default-src https://*; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* chrome-extension: about:; report-uri /csp_report;"
|
csp.value.should_not =~ /http:/
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when supplying an experimental block" do
|
context "when supplying an experimental block" do
|
||||||
|
@ -380,12 +393,12 @@ module SecureHeaders
|
||||||
|
|
||||||
it "uses the value in the experimental block over SSL" do
|
it "uses the value in the experimental block over SSL" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX, '/', :ssl => true), options, :experimental => true)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX, '/', :ssl => true), options, :experimental => true)
|
||||||
csp.value.should == "allow 'self'; script-src 'self';"
|
csp.value.should == "allow 'self'; img-src data:; script-src 'self';"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "merges the values from experimental/http_additions when not over SSL" do
|
it "merges the values from experimental/http_additions when not over SSL" do
|
||||||
csp = ContentSecurityPolicy.new(request_for(FIREFOX), options, :experimental => true)
|
csp = ContentSecurityPolicy.new(request_for(FIREFOX), options, :experimental => true)
|
||||||
csp.value.should == "allow 'self'; script-src 'self' https://mycdn.example.com;"
|
csp.value.should == "allow 'self'; img-src data:; script-src 'self' https://mycdn.example.com;"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче