Permalink
Browse files

Merge pull request #75 from twitter/standard_header_only

Standard header only
  • Loading branch information...
2 parents 5cf8221 + 01241b5 commit b4013c414e6473178f9d4a31150acc46387ac4b6 Neil Matatall committed Nov 11, 2013
View
@@ -7,8 +7,11 @@ group :test do
gem 'sqlite3', :platform => [:ruby, :mswin, :mingw]
gem 'jdbc-sqlite3', :platform => :jruby
gem 'rspec-rails'
- gem 'guard-spork'
- gem 'guard-rspec'
+ gem 'spork'
+ gem 'pry'
+ gem 'rspec'
+ gem 'guard-spork', :platform => :ruby_19
+ gem 'guard-rspec', :platform => :ruby_19
gem 'growl'
gem 'rb-fsevent'
gem 'simplecov'
View
@@ -49,13 +49,11 @@ The following methods are going to be called, unless they are provided in a `ski
* `:set_x_xss_protection_header`
* `:set_x_content_type_options_header`
-### Automagic
+### Bonus Features
This gem makes a few assumptions about how you will use some features. For example:
-* It adds 'chrome-extension:' to your CSP directives by default. This helps drastically reduce the amount of reports, but you can also disable this feature by supplying `:disable_chrome_extension => true`.
-* It fills any blank directives with the value in `:default_src` Getting a default\-src report is pretty useless. This way, you will always know what type of violation occurred. You can disable this feature by supplying `:disable_fill_missing => true`.
-* It copies the connect\-src value to xhr\-src for AJAX requests when using Firefox.
+* It fills any blank directives with the value in `:default_src` Getting a default\-src report is pretty useless. This way, you will always know what type of violation occurred. You can disable this feature by supplying `:disable_fill_missing => true`. This is referred to as the "effective-directive" in the spec, but is not well supported as of Nov 5, 2013.
* Firefox does not support cross\-origin CSP reports. If we are using Firefox, AND the value for `:report_uri` does not satisfy the same\-origin requirements, we will instead forward to an internal endpoint (`FF_CSP_ENDPOINT`). This is also the case if `:report_uri` only contains a path, which we assume will be cross host. This endpoint will in turn forward the request to the value in `:forward_endpoint` without restriction. More information can be found in the "Note on Firefox handling of CSP" section.
@@ -77,8 +75,10 @@ This gem makes a few assumptions about how you will use some features. For exam
}
end
-# and then simply include this in application_controller
-ensure_security_headers
+# and then simply include this in application_controller.rb
+class ApplicationController < ActionController::Base
+ ensure_security_headers
+end
```
Or simply add it to application controller
@@ -98,12 +98,15 @@ Each header configuration can take a hash, or a string, or both. If a string
is provided, that value is inserted verbatim. If a hash is supplied, a
header will be constructed using the supplied options.
-### Widely supported
+### The Easy Headers
+
+This configuration will likely work for most applications without modification.
```ruby
-:hsts => {:max_age => 631138519, :include_subdomains => true}
+:hsts => {:max_age => 631138519, :include_subdomains => false}
:x_frame_options => {:value => 'SAMEORIGIN'}
:x_xss_protection => {:value => 1, :mode => 'block'} # set the :mode option to false to use "warning only" mode
+:x_content_type_options => {:value => 'nosniff'}
```
### Content Security Policy (CSP)
@@ -159,49 +162,35 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
:img_src => 'http://mycdn.example.com'
}
}
-
+
# script-nonce is an experimental feature of CSP 1.1 available in Chrome. It allows
# you to whitelist inline script blocks. For more information, see
# https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-nonce
- :script_nonce => { 'abc123' }
-
- # you can also use lambdas to use dynamically generated nonces
- :script_nonce => lambda { @script_nonce] = 'something' }
+ :script_nonce => lambda { @script_nonce = SecureRandom.hex }
# which can be used to whitelist a script block:
# script_tag :nonce = @script_nonce { inline_script_call() }
}
```
-### Only applied to IE
-
-```ruby
-:x_content_type_options => {:value => 'nosniff'}
-```
-
### Example CSP header config
-**Configure the CSP header as if it were the webkit-style header, no need to supply 'options' or 'allow' directives.**
```ruby
# most basic example
:csp => {
:default_src => "https://* inline eval",
:report_uri => '/uri-directive'
}
-# Chrome
-> "default-src 'unsafe-inline' 'unsafe-eval' https://* chrome-extension:; report-uri /uri-directive;"
-# Firefox
-> "options inline-script eval-script; allow https://*; report-uri /uri-directive;"
+
+> "default-src 'unsafe-inline' 'unsafe-eval' https://*; report-uri /uri-directive;"
# turn off inline scripting/eval
:csp => {
:default_src => 'https://*',
:report_uri => '/uri-directive'
}
-# Chrome
+
> "default-src https://*; report-uri /uri-directive;"
-# Firefox
-> "allow https://*; report-uri /uri-directive;"
# Auction site wants to allow images from anywhere, plugin content from a list of trusted media providers (including a content distribution network), and scripts only from its server hosting sanitized JavaScript
:csp => {
@@ -211,19 +200,14 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
# alternatively (NOT csv) :object_src => 'media1.com media2.com *.cdn.com'
:script_src => 'trustedscripts.example.com'
}
-# Chrome
"default-src 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
-# Firefox
-"allow 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
```
## Note on Firefox handling of CSP
Currently, Firefox does not support the w3c draft standard. So there are a few steps taken to make the two interchangeable.
-* inline\-script or eval\-script values in default/style/script\-src directives are moved to the options directive. Note: the style\-src directive is not fully supported in Firefox \- see https://bugzilla.mozilla.org/show_bug.cgi?id=763879.
* CSP reports will not POST cross\-origin. This sets up an internal endpoint in the application that will forward the request. Set the `forward_endpoint` value in the CSP section if you need to post cross origin for firefox. The internal endpoint that receives the initial request will forward the request to `forward_endpoint`
-* Firefox adds port numbers to each /https?/ value which can make local development tricky with mocked services. Add environment specific code to configure this.
### Adding the Firefox report forwarding endpoint
@@ -19,7 +19,7 @@
it "sets the X-WebKit-CSP header" do
get :index
- response.headers['X-WebKit-CSP-Report-Only'].should == "default-src 'self'; img-src data:; report-uri somewhere;"
+ response.headers['Content-Security-Policy-Report-Only'].should == "default-src 'self'; img-src data:; report-uri somewhere;"
end
#mock ssl
@@ -23,7 +23,7 @@
it "sets the X-WebKit-CSP header" do
get :index
- response.headers['X-WebKit-CSP-Report-Only'].should == nil
+ response.headers['Content-Security-Policy-Report-Only'].should == nil
end
#mock ssl
@@ -47,6 +47,3 @@
end
end
end
-
-
-# response.headers['X-WebKit-CSP-Report-Only'].should == "default-src 'self'; report-uri somewhere"
@@ -19,7 +19,7 @@
it "sets the X-WebKit-CSP header" do
get :index
- response.headers['X-WebKit-CSP-Report-Only'].should == "default-src 'self'; img-src data:;"
+ response.headers['Content-Security-Policy-Report-Only'].should == "default-src 'self'; img-src data:;"
end
#mock ssl
@@ -23,7 +23,7 @@
it "sets the X-WebKit-CSP header" do
get :index
- response.headers['X-WebKit-CSP-Report-Only'].should == nil
+ response.headers['Content-Security-Policy-Report-Only'].should == nil
end
#mock ssl
View
@@ -48,8 +48,13 @@ def options_for(type, options)
end
module InstanceMethods
- def brwsr
- @secure_headers_brwsr ||= Brwsr::Browser.new(:ua => request.env['HTTP_USER_AGENT'])
+ # Re-added for backwards compat.
+ def set_security_headers(options = self.class.secure_headers_options)
+ set_csp_header(request, options[:csp])
+ set_hsts_header(options[:hsts])
+ set_x_frame_options_header(options[:x_frame_options])
+ set_x_xss_protection_header(options[:x_xss_protection])
+ set_x_content_type_options_header(options[:x_content_type_options])
end
# backwards compatibility jank, to be removed in 1.0. Old API required a request
@@ -59,12 +64,9 @@ def brwsr
# 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)
-
+ # hack to help generating headers statically
if req.is_a?(Hash)
options = req
- elsif req
- @secure_headers_brwsr = Brwsr::Browser.new(:ua => req.env['HTTP_USER_AGENT'])
end
options = self.class.secure_headers_options[:csp] if options.nil?
@@ -85,7 +87,6 @@ def set_x_frame_options_header(options=self.class.secure_headers_options[:x_fram
end
def set_x_content_type_options_header(options=self.class.secure_headers_options[:x_content_type_options])
- return unless brwsr.ie? || brwsr.chrome?
set_a_header(:x_content_type_options, XContentTypeOptions, options)
end
@@ -116,24 +117,15 @@ def set_header(name_or_header, value=nil)
response.headers[name_or_header] = value
end
end
-
- def broken_implementation?(browser)
- return browser.ios5? || (browser.safari? && browser.version == '5')
- end
end
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"
-require "secure_headers/headers/content_security_policy/ie_browser_strategy"
-require "secure_headers/headers/content_security_policy/standard_browser_strategy"
require "secure_headers/headers/x_frame_options"
require "secure_headers/headers/strict_transport_security"
require "secure_headers/headers/x_xss_protection"
require "secure_headers/headers/x_content_type_options"
require "secure_headers/railtie"
-require "brwsr"
Oops, something went wrong.

0 comments on commit b4013c4

Please sign in to comment.