Merge branch 'gh52_canonical_header_chrome'
This commit is contained in:
Коммит
3ca68eca61
|
@ -59,6 +59,8 @@ module SecureHeaders
|
|||
# set_csp_header(+Hash+) - uses the request accessor and options from parameters
|
||||
# set_csp_header(+Rack::Request+, +Hash+)
|
||||
def set_csp_header(req = nil, options=nil)
|
||||
return if broken_implementation?(brwsr)
|
||||
|
||||
if req.is_a?(Hash)
|
||||
options = req
|
||||
elsif req
|
||||
|
@ -66,17 +68,15 @@ module SecureHeaders
|
|||
end
|
||||
|
||||
options = self.class.secure_headers_options[:csp] if options.nil?
|
||||
|
||||
return if broken_implementation?(brwsr)
|
||||
|
||||
options = self.class.options_for :csp, options
|
||||
|
||||
return if options == false
|
||||
|
||||
header = ContentSecurityPolicy.new(options, :request => request, :controller => self)
|
||||
set_header(header.name, header.value)
|
||||
csp_header = ContentSecurityPolicy.new(options, :request => request, :controller => self)
|
||||
set_header(csp_header)
|
||||
if options && options[:experimental] && options[:enforce]
|
||||
header = ContentSecurityPolicy.new(options, :experimental => true, :request => request, :controller => self)
|
||||
set_header(header.name, header.value)
|
||||
experimental_header = ContentSecurityPolicy.new(options, :experimental => true, :request => request, :controller => self)
|
||||
set_header(experimental_header)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -105,11 +105,16 @@ module SecureHeaders
|
|||
return if options == false
|
||||
|
||||
header = klass.new(options)
|
||||
set_header(header.name, header.value)
|
||||
set_header(header)
|
||||
end
|
||||
|
||||
def set_header(name, value)
|
||||
response.headers[name] = value
|
||||
def set_header(name_or_header, value=nil)
|
||||
if name_or_header.is_a?(Header)
|
||||
header = name_or_header
|
||||
response.headers[header.name] = header.value
|
||||
else
|
||||
response.headers[name_or_header] = value
|
||||
end
|
||||
end
|
||||
|
||||
def broken_implementation?(browser)
|
||||
|
@ -120,6 +125,7 @@ end
|
|||
|
||||
|
||||
require "secure_headers/version"
|
||||
require "secure_headers/header"
|
||||
require "secure_headers/headers/content_security_policy"
|
||||
require "secure_headers/headers/content_security_policy/browser_strategy"
|
||||
require "secure_headers/headers/content_security_policy/firefox_browser_strategy"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
module SecureHeaders
|
||||
class Header
|
||||
|
||||
end
|
||||
end
|
|
@ -3,7 +3,7 @@ require 'brwsr'
|
|||
|
||||
module SecureHeaders
|
||||
class ContentSecurityPolicyBuildError < StandardError; end
|
||||
class ContentSecurityPolicy
|
||||
class ContentSecurityPolicy < Header
|
||||
module Constants
|
||||
WEBKIT_CSP_HEADER = "default-src https: data: 'unsafe-inline' 'unsafe-eval'; frame-src https://* about: javascript:; img-src chrome-extension:"
|
||||
FIREFOX_CSP_HEADER = "options eval-script inline-script; allow https://* data:; frame-src https://* about: javascript:; img-src chrome-extension:"
|
||||
|
|
|
@ -2,7 +2,11 @@ module SecureHeaders
|
|||
class ContentSecurityPolicy
|
||||
class WebkitBrowserStrategy < BrowserStrategy
|
||||
def base_name
|
||||
SecureHeaders::ContentSecurityPolicy::WEBKIT_CSP_HEADER_NAME
|
||||
if browser.chrome? && browser.version.to_i >= 25
|
||||
SecureHeaders::ContentSecurityPolicy::STANDARD_HEADER_NAME
|
||||
else
|
||||
SecureHeaders::ContentSecurityPolicy::WEBKIT_CSP_HEADER_NAME
|
||||
end
|
||||
end
|
||||
|
||||
def add_missing_extension_values
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module SecureHeaders
|
||||
class STSBuildError < StandardError; end
|
||||
|
||||
class StrictTransportSecurity
|
||||
class StrictTransportSecurity < Header
|
||||
module Constants
|
||||
HSTS_HEADER_NAME = 'Strict-Transport-Security'
|
||||
HSTS_MAX_AGE = "631138519"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module SecureHeaders
|
||||
class XContentTypeOptionsBuildError < StandardError; end
|
||||
# IE only
|
||||
class XContentTypeOptions
|
||||
class XContentTypeOptions < Header
|
||||
module Constants
|
||||
X_CONTENT_TYPE_OPTIONS_HEADER_NAME = "X-Content-Type-Options"
|
||||
DEFAULT_VALUE = "nosniff"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module SecureHeaders
|
||||
class XFOBuildError < StandardError; end
|
||||
class XFrameOptions
|
||||
class XFrameOptions < Header
|
||||
module Constants
|
||||
XFO_HEADER_NAME = "X-Frame-Options"
|
||||
DEFAULT_VALUE = 'SAMEORIGIN'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module SecureHeaders
|
||||
class XXssProtectionBuildError < StandardError; end
|
||||
class XXssProtection
|
||||
class XXssProtection < Header
|
||||
module Constants
|
||||
X_XSS_PROTECTION_HEADER_NAME = 'X-XSS-Protection'
|
||||
DEFAULT_VALUE = "1"
|
||||
|
|
|
@ -18,6 +18,8 @@ module SecureHeaders
|
|||
FIREFOX = "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.0.2) Gecko/20121223 Ubuntu/9.25 (jaunty) Firefox/3.8"
|
||||
FIREFOX_18 = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:18.0) Gecko/18.0 Firefox/18.0"
|
||||
CHROME = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4"
|
||||
CHROME_25 = "Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/537.22 (KHTML like Gecko) Chrome/25.0.1364.99 Safari/537.22"
|
||||
|
||||
|
||||
def request_for user_agent, request_uri=nil, options={:ssl => false}
|
||||
double(:ssl? => options[:ssl], :env => {'HTTP_USER_AGENT' => user_agent}, :url => (request_uri || 'http://areallylongdomainexample.com') )
|
||||
|
@ -32,12 +34,14 @@ module SecureHeaders
|
|||
specify { ContentSecurityPolicy.new(default_opts, :ua => IE).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :ua => FIREFOX).name.should == FIREFOX_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :ua => CHROME).name.should == WEBKIT_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :ua => CHROME_25).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
end
|
||||
|
||||
context "when in report-only mode" do
|
||||
specify { ContentSecurityPolicy.new(default_opts, :request => request_for(IE)).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :request => request_for(FIREFOX)).name.should == FIREFOX_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :request => request_for(CHROME)).name.should == WEBKIT_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(default_opts, :request => request_for(CHROME_25)).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
end
|
||||
|
||||
context "when in enforce mode" do
|
||||
|
@ -46,6 +50,7 @@ module SecureHeaders
|
|||
specify { ContentSecurityPolicy.new(opts, :request => request_for(IE)).name.should == STANDARD_HEADER_NAME}
|
||||
specify { ContentSecurityPolicy.new(opts, :request => request_for(FIREFOX)).name.should == FIREFOX_CSP_HEADER_NAME}
|
||||
specify { ContentSecurityPolicy.new(opts, :request => request_for(CHROME)).name.should == WEBKIT_CSP_HEADER_NAME}
|
||||
specify { ContentSecurityPolicy.new(opts, :request => request_for(CHROME_25)).name.should == STANDARD_HEADER_NAME}
|
||||
end
|
||||
|
||||
context "when in experimental mode" do
|
||||
|
@ -53,6 +58,7 @@ module SecureHeaders
|
|||
specify { ContentSecurityPolicy.new(opts, {:experimental => true, :request => request_for(IE)}).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(opts, {:experimental => true, :request => request_for(FIREFOX)}).name.should == FIREFOX_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(opts, {:experimental => true, :request => request_for(CHROME)}).name.should == WEBKIT_CSP_HEADER_NAME + "-Report-Only"}
|
||||
specify { ContentSecurityPolicy.new(opts, {:experimental => true, :request => request_for(CHROME_25)}).name.should == STANDARD_HEADER_NAME + "-Report-Only"}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -31,11 +31,11 @@ describe SecureHeaders do
|
|||
}
|
||||
|
||||
def should_assign_header name, value
|
||||
subject.should_receive(:set_header).with(name, value)
|
||||
response.headers.should_receive(:[]=).with(name, value)
|
||||
end
|
||||
|
||||
def should_not_assign_header name
|
||||
subject.should_not_receive(:set_header).with(name, anything)
|
||||
response.headers.should_not_receive(:[]=).with(name, anything)
|
||||
end
|
||||
|
||||
def stub_user_agent val
|
||||
|
@ -72,6 +72,18 @@ describe SecureHeaders do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#set_header" do
|
||||
it "accepts name/value pairs" do
|
||||
should_assign_header("X-Hipster-Ipsum", "kombucha")
|
||||
subject.send(:set_header, "X-Hipster-Ipsum", "kombucha")
|
||||
end
|
||||
|
||||
it "accepts header objects" do
|
||||
should_assign_header("Strict-Transport-Security", SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)
|
||||
subject.send(:set_header, SecureHeaders::StrictTransportSecurity.new)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#set_security_headers" do
|
||||
before(:each) do
|
||||
SecureHeaders::ContentSecurityPolicy.stub(:new).and_return(double.as_null_object)
|
||||
|
@ -262,13 +274,13 @@ describe SecureHeaders do
|
|||
opts = @opts.merge(:enforce => false)
|
||||
should_assign_header(WEBKIT_CSP_HEADER_NAME + "-Report-Only", anything)
|
||||
should_not_assign_header(WEBKIT_CSP_HEADER_NAME)
|
||||
subject.set_csp_header opts
|
||||
subject.set_csp_header(opts)
|
||||
end
|
||||
|
||||
it "sets a header in enforce mode as well as report-only mode" do
|
||||
should_assign_header(WEBKIT_CSP_HEADER_NAME, anything)
|
||||
should_assign_header(WEBKIT_CSP_HEADER_NAME + "-Report-Only", anything)
|
||||
subject.set_csp_header @opts
|
||||
subject.set_csp_header(@opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче