secure_headers 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. data/.gitignore +4 -8
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +8 -3
  5. data/Gemfile +6 -8
  6. data/README.md +208 -134
  7. data/Rakefile +11 -116
  8. data/fixtures/rails_3_2_12/Gemfile +0 -8
  9. data/fixtures/rails_3_2_12/app/controllers/things_controller.rb +0 -1
  10. data/fixtures/rails_3_2_12/app/views/layouts/application.html.erb +1 -4
  11. data/fixtures/rails_3_2_12/app/views/other_things/index.html.erb +2 -1
  12. data/fixtures/rails_3_2_12/app/views/things/index.html.erb +1 -21
  13. data/fixtures/rails_3_2_12/config/application.rb +0 -54
  14. data/fixtures/rails_3_2_12/config/environments/test.rb +2 -2
  15. data/fixtures/rails_3_2_12/config/initializers/secure_headers.rb +3 -1
  16. data/fixtures/rails_3_2_12/config/routes.rb +0 -57
  17. data/fixtures/rails_3_2_12/config/script_hashes.yml +5 -0
  18. data/fixtures/rails_3_2_12/config.ru +3 -0
  19. data/fixtures/rails_3_2_12/spec/controllers/other_things_controller_spec.rb +57 -19
  20. data/fixtures/rails_3_2_12/spec/controllers/things_controller_spec.rb +18 -16
  21. data/fixtures/rails_3_2_12/spec/spec_helper.rb +1 -5
  22. data/fixtures/rails_3_2_12_no_init/Gemfile +0 -9
  23. data/fixtures/rails_3_2_12_no_init/app/controllers/other_things_controller.rb +1 -2
  24. data/fixtures/rails_3_2_12_no_init/app/controllers/things_controller.rb +1 -1
  25. data/fixtures/rails_3_2_12_no_init/app/views/layouts/application.html.erb +0 -2
  26. data/fixtures/rails_3_2_12_no_init/app/views/things/index.html.erb +0 -21
  27. data/fixtures/rails_3_2_12_no_init/config/application.rb +0 -51
  28. data/fixtures/rails_3_2_12_no_init/config/environments/test.rb +2 -2
  29. data/fixtures/rails_3_2_12_no_init/config/routes.rb +0 -57
  30. data/fixtures/rails_3_2_12_no_init/spec/controllers/other_things_controller_spec.rb +17 -12
  31. data/fixtures/rails_3_2_12_no_init/spec/controllers/things_controller_spec.rb +17 -12
  32. data/fixtures/rails_3_2_12_no_init/spec/spec_helper.rb +3 -18
  33. data/fixtures/rails_4_1_8/Gemfile +5 -0
  34. data/fixtures/rails_4_1_8/README.rdoc +28 -0
  35. data/fixtures/rails_4_1_8/Rakefile +6 -0
  36. data/fixtures/rails_4_1_8/app/controllers/application_controller.rb +4 -0
  37. data/fixtures/rails_4_1_8/app/controllers/concerns/.keep +0 -0
  38. data/fixtures/rails_4_1_8/app/controllers/other_things_controller.rb +5 -0
  39. data/fixtures/rails_4_1_8/app/controllers/things_controller.rb +5 -0
  40. data/fixtures/rails_4_1_8/app/models/.keep +0 -0
  41. data/fixtures/rails_4_1_8/app/models/concerns/.keep +0 -0
  42. data/fixtures/rails_4_1_8/app/views/layouts/application.html.erb +11 -0
  43. data/fixtures/rails_4_1_8/app/views/other_things/index.html.erb +2 -0
  44. data/fixtures/rails_4_1_8/app/views/things/index.html.erb +1 -0
  45. data/fixtures/rails_4_1_8/config/application.rb +15 -0
  46. data/fixtures/rails_4_1_8/config/boot.rb +4 -0
  47. data/fixtures/rails_4_1_8/config/environment.rb +5 -0
  48. data/fixtures/rails_4_1_8/config/environments/test.rb +10 -0
  49. data/fixtures/rails_4_1_8/config/initializers/secure_headers.rb +17 -0
  50. data/fixtures/rails_4_1_8/config/routes.rb +4 -0
  51. data/fixtures/rails_4_1_8/config/script_hashes.yml +5 -0
  52. data/fixtures/rails_4_1_8/config/secrets.yml +22 -0
  53. data/fixtures/rails_4_1_8/config.ru +4 -0
  54. data/fixtures/rails_4_1_8/lib/assets/.keep +0 -0
  55. data/fixtures/rails_4_1_8/lib/tasks/.keep +0 -0
  56. data/fixtures/rails_4_1_8/log/.keep +0 -0
  57. data/fixtures/rails_4_1_8/spec/controllers/other_things_controller_spec.rb +83 -0
  58. data/fixtures/rails_4_1_8/spec/controllers/things_controller_spec.rb +59 -0
  59. data/fixtures/rails_4_1_8/spec/spec_helper.rb +15 -0
  60. data/fixtures/rails_4_1_8/vendor/assets/javascripts/.keep +0 -0
  61. data/fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep +0 -0
  62. data/lib/secure_headers/hash_helper.rb +7 -0
  63. data/lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb +22 -0
  64. data/lib/secure_headers/headers/content_security_policy.rb +160 -161
  65. data/lib/secure_headers/headers/strict_transport_security.rb +2 -1
  66. data/lib/secure_headers/headers/x_download_options.rb +39 -0
  67. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +40 -0
  68. data/lib/secure_headers/headers/x_xss_protection.rb +2 -1
  69. data/lib/secure_headers/padrino.rb +14 -0
  70. data/lib/secure_headers/railtie.rb +19 -24
  71. data/lib/secure_headers/version.rb +1 -1
  72. data/lib/secure_headers/view_helper.rb +68 -0
  73. data/lib/secure_headers.rb +70 -29
  74. data/lib/tasks/tasks.rake +48 -0
  75. data/secure_headers.gemspec +4 -5
  76. data/spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb +47 -0
  77. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +127 -299
  78. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +21 -20
  79. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +12 -12
  80. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +32 -0
  81. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +12 -13
  82. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +64 -0
  83. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +20 -19
  84. data/spec/lib/secure_headers_spec.rb +68 -83
  85. data/spec/spec_helper.rb +29 -18
  86. metadata +51 -66
  87. data/.rvmrc +0 -1
  88. data/Guardfile +0 -10
  89. data/HISTORY.md +0 -100
  90. data/app/controllers/content_security_policy_controller.rb +0 -53
  91. data/config/curl-ca-bundle.crt +0 -5420
  92. data/config/routes.rb +0 -3
  93. data/fixtures/rails_3_2_12/Guardfile +0 -14
  94. data/fixtures/rails_3_2_12/app/models/thing.rb +0 -3
  95. data/fixtures/rails_3_2_12/config/database.yml +0 -25
  96. data/fixtures/rails_3_2_12/config/environments/development.rb +0 -37
  97. data/fixtures/rails_3_2_12/config/environments/production.rb +0 -67
  98. data/fixtures/rails_3_2_12/config/initializers/backtrace_silencers.rb +0 -7
  99. data/fixtures/rails_3_2_12/config/initializers/inflections.rb +0 -15
  100. data/fixtures/rails_3_2_12/config/initializers/mime_types.rb +0 -5
  101. data/fixtures/rails_3_2_12/config/initializers/secret_token.rb +0 -7
  102. data/fixtures/rails_3_2_12/config/initializers/session_store.rb +0 -8
  103. data/fixtures/rails_3_2_12/config/initializers/wrap_parameters.rb +0 -14
  104. data/fixtures/rails_3_2_12/config/locales/en.yml +0 -5
  105. data/fixtures/rails_3_2_12/db/schema.rb +0 -16
  106. data/fixtures/rails_3_2_12/db/seeds.rb +0 -7
  107. data/fixtures/rails_3_2_12_no_init/Guardfile +0 -14
  108. data/fixtures/rails_3_2_12_no_init/app/models/thing.rb +0 -3
  109. data/fixtures/rails_3_2_12_no_init/app/views/things/_form.html.erb +0 -17
  110. data/fixtures/rails_3_2_12_no_init/app/views/things/edit.html.erb +0 -6
  111. data/fixtures/rails_3_2_12_no_init/app/views/things/new.html.erb +0 -5
  112. data/fixtures/rails_3_2_12_no_init/app/views/things/show.html.erb +0 -5
  113. data/fixtures/rails_3_2_12_no_init/config/database.yml +0 -25
  114. data/fixtures/rails_3_2_12_no_init/config/environments/development.rb +0 -37
  115. data/fixtures/rails_3_2_12_no_init/config/environments/production.rb +0 -67
  116. data/fixtures/rails_3_2_12_no_init/config/initializers/backtrace_silencers.rb +0 -7
  117. data/fixtures/rails_3_2_12_no_init/config/initializers/inflections.rb +0 -15
  118. data/fixtures/rails_3_2_12_no_init/config/initializers/mime_types.rb +0 -5
  119. data/fixtures/rails_3_2_12_no_init/config/initializers/secret_token.rb +0 -7
  120. data/fixtures/rails_3_2_12_no_init/config/initializers/session_store.rb +0 -8
  121. data/fixtures/rails_3_2_12_no_init/config/initializers/wrap_parameters.rb +0 -14
  122. data/fixtures/rails_3_2_12_no_init/config/locales/en.yml +0 -5
  123. data/fixtures/rails_3_2_12_no_init/db/schema.rb +0 -16
  124. data/fixtures/rails_3_2_12_no_init/db/seeds.rb +0 -7
  125. data/lib/secure_headers/headers/content_security_policy/browser_strategy.rb +0 -78
  126. data/lib/secure_headers/headers/content_security_policy/firefox_browser_strategy.rb +0 -72
  127. data/lib/secure_headers/headers/content_security_policy/ie_browser_strategy.rb +0 -6
  128. data/lib/secure_headers/headers/content_security_policy/standard_browser_strategy.rb +0 -22
  129. data/spec/controllers/content_security_policy_controller_spec.rb +0 -74
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.gem
2
+ *.DS_STORE
2
3
  *.rbc
3
4
  .bundle
4
5
  .config
@@ -15,12 +16,7 @@ rdoc
15
16
  spec/reports
16
17
  test/tmp
17
18
  test/version_tmp
18
- tmp
19
-
20
- /fixtures/rails_3_2_12/log/test.log
21
- /fixtures/rails_3_2_12_no_init/log/test.log
19
+ *tmp
22
20
  *.sqlite3
23
- test.sqlite3
24
- *test.sqlite3
25
- /fixtures/rails_3_2_12_no_init/db/test.sqlite3
26
- /fixtures/rails_3_2_12/db/test.sqlite3
21
+ fixtures/rails_3_2_12_no_init/log
22
+ fixtures/rails_3_2_12/log
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ secureheaders
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p484
data/.travis.yml CHANGED
@@ -1,6 +1,11 @@
1
+ language: ruby
2
+
1
3
  rvm:
4
+ - "2.1"
5
+ - "2.0.0"
2
6
  - "1.9.3"
3
7
  - "1.8.7"
4
- # - jruby-19mode
5
- # - jruby-18mode
6
- #script: ./travis.sh
8
+ - "jruby-19mode"
9
+
10
+ sudo: false
11
+ cache: bundler
data/Gemfile CHANGED
@@ -4,14 +4,12 @@ gemspec
4
4
 
5
5
  group :test do
6
6
  gem 'rails', '3.2.12'
7
- gem 'sqlite3', :platform => [:ruby, :mswin, :mingw]
8
- gem 'jdbc-sqlite3', :platform => :jruby
9
- gem 'rspec-rails'
10
- gem 'guard-spork'
11
- gem 'guard-rspec'
7
+ gem 'sqlite3', :platforms => [:ruby, :mswin, :mingw]
8
+ gem 'jdbc-sqlite3', :platforms => [:jruby]
9
+ gem 'rspec-rails', '>= 3.1'
10
+ gem 'rspec', '>= 3.1'
12
11
  gem 'growl'
13
12
  gem 'rb-fsevent'
14
- gem 'simplecov'
15
- gem 'debugger', :platform => :ruby_19
16
- gem 'ruby-debug', :platform => :ruby_18
13
+ gem 'coveralls', :platforms => [:ruby_19]
14
+ gem 'i18n', '< 0.7.0', :platforms => [:ruby_18]
17
15
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SecureHeaders [![Build Status](https://travis-ci.org/twitter/secureheaders.png?branch=master)](http://travis-ci.org/twitter/secureheaders) [![Code Climate](https://codeclimate.com/github/twitter/secureheaders.png)](https://codeclimate.com/github/twitter/secureheaders)
1
+ # SecureHeaders [![Build Status](https://travis-ci.org/twitter/secureheaders.png?branch=master)](http://travis-ci.org/twitter/secureheaders) [![Code Climate](https://codeclimate.com/github/twitter/secureheaders.png)](https://codeclimate.com/github/twitter/secureheaders) [![Coverage Status](https://coveralls.io/repos/twitter/secureheaders/badge.png)](https://coveralls.io/r/twitter/secureheaders)
2
2
 
3
3
  The gem will automatically apply several headers that are related to security. This includes:
4
4
  - Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 1.1 Specification](https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html)
@@ -6,36 +6,12 @@ The gem will automatically apply several headers that are related to security.
6
6
  - X-Frame-Options (XFO) - Prevents your content from being framed and potentially clickjacked. [X-Frame-Options draft](https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02)
7
7
  - X-XSS-Protection - [Cross site scripting heuristic filter for IE/Chrome](http://msdn.microsoft.com/en-us/library/dd565647\(v=vs.85\).aspx)
8
8
  - X-Content-Type-Options - [Prevent content type sniffing](http://msdn.microsoft.com/en-us/library/ie/gg622941\(v=vs.85\).aspx)
9
-
10
- This gem has integration with Rails, but works for any Ruby code. See the sinatra example section.
11
-
12
- ## Installation
13
-
14
- Add to your Gemfile
15
-
16
- ```ruby
17
- gem 'secure_headers'
18
- ```
19
-
20
- And then execute:
21
-
22
- ```console
23
- $ bundle
24
- ```
25
-
26
- Or install it yourself as:
27
-
28
- ```console
29
- $ gem install secure_headers
30
- ```
9
+ - X-Download-Options - [Prevent file downloads opening](http://msdn.microsoft.com/en-us/library/ie/jj542450(v=vs.85).aspx)
10
+ - X-Permitted-Cross-Domain-Policies - [Restrict Adobe Flash Player's access to data](https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html)
31
11
 
32
12
  ## Usage
33
13
 
34
- Functionality provided
35
-
36
- - `ensure_security_headers`: will set security-related headers automatically based on the configuration below.
37
-
38
- By default, it will set all of the headers listed in the options section below unless specified.
14
+ - `ensure_security_headers` in a controller will set security-related headers automatically based on the configuration below.
39
15
 
40
16
  ### Disabling
41
17
 
@@ -48,16 +24,14 @@ The following methods are going to be called, unless they are provided in a `ski
48
24
  * `:set_x_frame_options_header`
49
25
  * `:set_x_xss_protection_header`
50
26
  * `:set_x_content_type_options_header`
27
+ * `:set_x_download_options_header`
28
+ * `:set_x_permitted_cross_domain_policies_header`
51
29
 
52
- ### Automagic
30
+ ### Bonus Features
53
31
 
54
32
  This gem makes a few assumptions about how you will use some features. For example:
55
33
 
56
- * 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`.
57
- * 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`.
58
- * It copies the connect\-src value to xhr\-src for AJAX requests when using Firefox.
59
- * 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.
60
-
34
+ * 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.
61
35
 
62
36
  ## Configuration
63
37
 
@@ -65,29 +39,34 @@ This gem makes a few assumptions about how you will use some features. For exam
65
39
 
66
40
  ```ruby
67
41
  ::SecureHeaders::Configuration.configure do |config|
68
- config.hsts = {:max_age => 99, :include_subdomains => true}
42
+ config.hsts = {:max_age => 20.years.to_i, :include_subdomains => true}
69
43
  config.x_frame_options = 'DENY'
70
44
  config.x_content_type_options = "nosniff"
71
- config.x_xss_protection = {:value => 1, :mode => false}
45
+ config.x_xss_protection = {:value => 1, :mode => 'block'}
46
+ config.x_download_options = 'noopen'
47
+ config.x_permitted_cross_domain_policies = 'none'
72
48
  config.csp = {
73
- :default_src => "https://* inline eval",
74
- :report_uri => '//example.com/uri-directive',
75
- :img_src => "https://* data:",
76
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
49
+ :default_src => "https: self",
50
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com",
51
+ :img_src => "https:",
52
+ :report_uri => '//example.com/uri-directive'
77
53
  }
78
54
  end
79
55
 
80
- # and then simply include this in application_controller
81
- ensure_security_headers
56
+ # and then simply include this in application_controller.rb
57
+ class ApplicationController < ActionController::Base
58
+ ensure_security_headers
59
+ end
82
60
  ```
83
61
 
84
- Or simply add it to application controller (not recommended, currently a bug)
62
+ Or simply add it to application controller
85
63
 
86
64
  ```ruby
87
- ensure_security_headers
88
- :hsts => {:include_subdomains, :x_frame_options => false},
65
+ ensure_security_headers(
66
+ :hsts => {:include_subdomains => true, :max_age => 20.years.to_i},
89
67
  :x_frame_options => 'DENY',
90
68
  :csp => false
69
+ )
91
70
  ```
92
71
 
93
72
  ## Options for ensure\_security\_headers
@@ -98,20 +77,21 @@ Each header configuration can take a hash, or a string, or both. If a string
98
77
  is provided, that value is inserted verbatim. If a hash is supplied, a
99
78
  header will be constructed using the supplied options.
100
79
 
101
- ### Widely supported
80
+ ### The Easy Headers
81
+
82
+ This configuration will likely work for most applications without modification.
102
83
 
103
84
  ```ruby
104
- :hsts => {:max_age => 631138519, :include_subdomains => true}
85
+ :hsts => {:max_age => 631138519, :include_subdomains => false}
105
86
  :x_frame_options => {:value => 'SAMEORIGIN'}
106
- :x_xss_protection => {:value => 1, :mode => false} # set the :mode option to 'block' to enforce the browser's xss filter
87
+ :x_xss_protection => {:value => 1, :mode => 'block'} # set the :mode option to false to use "warning only" mode
88
+ :x_content_type_options => {:value => 'nosniff'}
89
+ :x_download_options => {:value => 'noopen'}
90
+ :x_permitted_cross_domain_policies => {:value => 'none'}
107
91
  ```
108
92
 
109
93
  ### Content Security Policy (CSP)
110
94
 
111
- All browsers will receive the webkit csp header except Firefox, which gets its own header.
112
- See [WebKit specification](http://www.w3.org/TR/CSP/)
113
- and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specification)
114
-
115
95
  ```ruby
116
96
  :csp => {
117
97
  :enforce => false, # sets header to report-only, by default
@@ -121,11 +101,6 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
121
101
  # Where reports are sent. Use protocol relative URLs if you are posting to the same domain (TLD+1). Use paths if you are posting to the application serving the header
122
102
  :report_uri => '//mysite.example.com',
123
103
 
124
- # Send reports that cannot be sent across host here. These requests are sent
125
- # the server, not the browser. If no value is supplied, it will default to
126
- # the value in report_uri. Use this if you cannot use relative protocols mentioned above due to host mismatches.
127
- :forward_endpoint => 'https://internal.mylogaggregator.example.com'
128
-
129
104
  # these directives all take 'none', 'self', or a globbed pattern
130
105
  :img_src => nil,
131
106
  :frame_src => nil,
@@ -140,68 +115,34 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
140
115
  # over http, relaxing the policy
141
116
  # e.g.
142
117
  # :csp => {
143
- # :img_src => 'https://*',
144
- # :http_additions => {:img_src => 'http//*'}
118
+ # :img_src => 'https:',
119
+ # :http_additions => {:img_src => 'http'}
145
120
  # }
146
- # would produce the directive: "img-src https://* http://*;"
121
+ # would produce the directive: "img-src https: http:;"
147
122
  # when over http, ignored for https requests
148
123
  :http_additions => {}
149
-
150
- # If you have enforce => true, you can use the `experiments` block to
151
- # also produce a report-only header. Values in this block override the
152
- # parent config for the report-only, and leave the enforcing header
153
- # unaltered. http_additions work the same way described above, but
154
- # are added to your report-only header as expected.
155
- :experimental => {
156
- :script_src => 'self',
157
- :img_src => 'https://mycdn.example.com',
158
- :http_additions {
159
- :img_src => 'http://mycdn.example.com'
160
- }
161
- }
162
-
163
- # script-nonce is an experimental feature of CSP 1.1 available in Chrome. It allows
164
- # you to whitelist inline script blocks. For more information, see
165
- # https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-nonce
166
- :script_nonce => { 'abc123' }
167
-
168
- # you can also use lambdas to use dynamically generated nonces
169
- :script_nonce => lambda { @script_nonce] = 'something' }
170
- # which can be used to whitelist a script block:
171
- # script_tag :nonce = @script_nonce { inline_script_call() }
172
124
  }
173
125
  ```
174
126
 
175
- ### Only applied to IE
176
-
177
- ```ruby
178
- :x_content_type_options => {:value => 'nosniff'}
179
- ```
180
-
181
127
  ### Example CSP header config
182
128
 
183
- **Configure the CSP header as if it were the webkit-style header, no need to supply 'options' or 'allow' directives.**
184
129
 
185
130
  ```ruby
186
131
  # most basic example
187
132
  :csp => {
188
- :default_src => "https://* inline eval",
133
+ :default_src => "https: inline eval",
189
134
  :report_uri => '/uri-directive'
190
135
  }
191
- # Chrome
192
- > "default-src 'unsafe-inline' 'unsafe-eval' https://* chrome-extension:; report-uri /uri-directive;"
193
- # Firefox
194
- > "options inline-script eval-script; allow https://*; report-uri /uri-directive;"
136
+
137
+ > "default-src 'unsafe-inline' 'unsafe-eval' https:; report-uri /uri-directive;"
195
138
 
196
139
  # turn off inline scripting/eval
197
140
  :csp => {
198
- :default_src => 'https://*',
141
+ :default_src => 'https:',
199
142
  :report_uri => '/uri-directive'
200
143
  }
201
- # Chrome
202
- > "default-src https://*; report-uri /uri-directive;"
203
- # Firefox
204
- > "allow https://*; report-uri /uri-directive;"
144
+
145
+ > "default-src https:; report-uri /uri-directive;"
205
146
 
206
147
  # 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
207
148
  :csp => {
@@ -211,38 +152,152 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
211
152
  # alternatively (NOT csv) :object_src => 'media1.com media2.com *.cdn.com'
212
153
  :script_src => 'trustedscripts.example.com'
213
154
  }
214
- # Chrome
215
155
  "default-src 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
216
- # Firefox
217
- "allow 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
218
156
  ```
219
157
 
220
- ## Note on Firefox handling of CSP
158
+ ### Tagging Requests
159
+
160
+ It's often valuable to send extra information in the report uri that is not available in the reports themselves. Namely, "was the policy enforced" and "where did the report come from"
161
+
162
+ ```ruby
163
+ {
164
+ :tag_report_uri => true,
165
+ :enforce => true,
166
+ :app_name => 'twitter',
167
+ :report_uri => 'csp_reports'
168
+ }
169
+ ```
170
+
171
+ Results in
172
+ ```
173
+ report-uri csp_reports?enforce=true&app_name=twitter
174
+ ```
221
175
 
222
- Currently, Firefox does not support the w3c draft standard. So there are a few steps taken to make the two interchangeable.
176
+ ### CSP Level 2 features
223
177
 
224
- * 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.
225
- * 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`
226
- * Ffirefox adds port numbers to each /https?/ value which can make local development tricky with mocked services. Add environment specific code to configure this.
178
+ *NOTE: Currently, only erb is supported. Mustache support isn't far off. Hash sources are valid for inline style blocks but are not yet supported by secure_headers.*
227
179
 
228
- ### Adding the Firefox report forwarding endpoint
180
+ #### Nonce
229
181
 
230
- **You need to add the following line to the TOP of confib/routes.rb**
231
- **This is an unauthenticated, unauthorized endpoint. Only do this if your report\-uri is not on the same origin as your application!!!**
182
+ script/style-nonce can be used to whitelist inline content. To do this, add "nonce" to your script/style-src configuration, then set the nonce attributes on the various tags.
232
183
 
233
- #### Rails 2
184
+ Setting a nonce will also set 'unsafe-inline' for browsers that don't support nonces for backwards compatibility. 'unsafe-inline' is ignored if a nonce is present in a directive in compliant browsers.
234
185
 
235
186
  ```ruby
236
- map.csp_endpoint
187
+ :csp => {
188
+ :default_src => 'self',
189
+ :script_src => 'self nonce'
190
+ }
237
191
  ```
238
192
 
239
- #### Rails 3
193
+ > content-security-policy: default-src 'self'; script-src 'self' 'nonce-abc123' 'unsafe-inline'
194
+
195
+ ```erb
196
+ <script nonce="<%= @content_security_policy_nonce %>">
197
+ console.log("whitelisted, will execute")
198
+ </script>
240
199
 
241
- If the csp reporting endpoint is clobbered by another route, add:
200
+ <script nonce="lol">
201
+ console.log("won't execute, not whitelisted")
202
+ </script>
203
+
204
+ <script>
205
+ console.log("won't execute, not whitelisted")
206
+ </script>
207
+ ```
208
+ You can use a view helper to automatically add nonces to script tags:
209
+ ```erb
210
+ <%= nonced_javascript_tag do %>
211
+ console.log("nonced!")
212
+ <% end %>
213
+ <%= nonced_javascript_tag("nonced without a block!") %>
214
+ ```
215
+
216
+ becomes:
217
+
218
+ ```html
219
+ <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
220
+ console.log("nonced!")
221
+ </script>
222
+ ```
223
+
224
+ #### Hash
225
+
226
+ setting hash source values will also set 'unsafe-inline' for browsers that don't support hash sources for backwards compatibility. 'unsafe-inline' is ignored if a hash is present in a directive in compliant browsers.
227
+
228
+ Hash source support works by taking the hash value of the contents of an inline script block and adding the hash "fingerprint" to the CSP header.
229
+
230
+ If you only have a few hashes, you can hardcode them for the entire app:
231
+
232
+ ```ruby
233
+ config.csp = {
234
+ :default_src => "https:",
235
+ :script_src => 'self'
236
+ :script_hashes => ['sha1-abc', 'sha1-qwe']
237
+ }
238
+ ```
239
+
240
+ The following will work as well, but may not be as clear:
241
+
242
+ ```ruby
243
+ config.csp = {
244
+ :default_src => "https:",
245
+ :script_src => "self 'sha1-qwe'"
246
+ }
247
+ ```
248
+
249
+ If you find you have many hashes or the content of the script tags change frequently, you can apply these hashes in a more intelligent way. This method expects config/script_hashes.yml to contain a map of templates => [hashes]. When the individual templates, layouts, or partials are rendered the hash values for the script tags in those templates will be automatically added to the header. *Currently, only erb layouts are supported.* This requires the use of middleware:
250
+
251
+ ```ruby
252
+ # config.ru
253
+ require 'secure_headers/headers/content_security_policy/script_hash_middleware'
254
+ use ::SecureHeaders::ContentSecurityPolicy::ScriptHashMiddleware
255
+ ```
242
256
 
243
257
  ```ruby
244
- post SecureHeaders::ContentSecurityPolicy::FF_CSP_ENDPOINT => "content_security_policy#scribe"
258
+ config.csp = {
259
+ :default_src => "https:",
260
+ :script_src => 'self',
261
+ :script_hash_middleware => true
262
+ }
263
+ ```
264
+
265
+ Hashes are stored in a yaml file with a mapping of Filename => [list of hashes] in config/script_hashes.yml. You can automatically populate this file by running the following rake task:
266
+
267
+ ```$ bundle exec rake secure_headers:generate_hashes```
268
+
269
+ Which will generate something like:
270
+
271
+ ```yaml
272
+ # config/script_hashes.yml
273
+ app/views/layouts/application.html.erb:
274
+ - sha256-l8OLjZqYRnKilpdE0VosRMvhdYArjXT4NZaK2p7QVvs=
275
+ app/templates/articles/edit.html.erb:
276
+ - sha256-+7mij1/uCwtCQRWrof2NmOln5qX+5WdVwTLMpi8nuoA=
277
+ - sha256-Ny4TRIhhFpnYnSeKC274P6bfAz4TOkezLabavIAU4dA=
278
+ - sha256-I5e58Gqbu4WpO9dck18QxO7aYOHKrELIi70it4jIPi0=
279
+ - sha256-Po4LMynwnAJHxiTp3DQaQ3YDBj3paN/xrDoKl4OyxY4=
280
+ ```
281
+
282
+ In this example, if we visit /articles/edit/[id], the above hashes will automatically be added to the CSP header's
283
+ script-src value!
284
+
285
+ You can use plain "script" tags or you can use a built-in helper:
286
+
287
+ ```erb
288
+ <%= hashed_javascript_tag do %>
289
+ console.log("hashed automatically!")
290
+ <% end %>
291
+ ```
292
+
293
+ By using the helper, hash values will be computed dynamically in development/test environments. If a dynamically computed hash value does not match what is expected to be found in config/script_hashes.yml a warning message will be printed to the console. If you want to raise exceptions instead, use:
294
+
295
+ ```erb
296
+ <%= hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
297
+ console.log("will raise an exception if not in script_hashes.yml!")
298
+ <% end %>
245
299
  ```
300
+
246
301
  ### Using with Sinatra
247
302
 
248
303
  Here's an example using SecureHeaders for Sinatra applications:
@@ -258,11 +313,13 @@ require 'secure_headers'
258
313
  config.x_frame_options = 'DENY'
259
314
  config.x_content_type_options = "nosniff"
260
315
  config.x_xss_protection = {:value => 1, :mode => false}
316
+ config.x_download_options = 'noopen'
317
+ config.x_permitted_cross_domain_policies = 'none'
261
318
  config.csp = {
262
- :default_src => "https://* inline eval",
319
+ :default_src => "https: inline eval",
263
320
  :report_uri => '//example.com/uri-directive',
264
- :img_src => "https://* data:",
265
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
321
+ :img_src => "https: data:",
322
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com"
266
323
  }
267
324
  end
268
325
 
@@ -290,22 +347,11 @@ In your `Gemfile`:
290
347
  then in your `app.rb` file you can:
291
348
 
292
349
  ```ruby
350
+ require 'secure_headers/padrino'
351
+
293
352
  module Web
294
353
  class App < Padrino::Application
295
- include SecureHeaders
296
-
297
- ::SecureHeaders::Configuration.configure do |config|
298
- config.hsts = {:max_age => 99, :include_subdomains => true}
299
- config.x_frame_options = 'DENY'
300
- config.x_content_type_options = "nosniff"
301
- config.x_xss_protection = {:value => '1', :mode => false}
302
- config.csp = {
303
- :default_src => "https://* inline eval",
304
- :report_uri => '//example.com/uri-directive',
305
- :img_src => "https://* data:",
306
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
307
- }
308
- end
354
+ register SecureHeaders::Padrino
309
355
 
310
356
  get '/' do
311
357
  set_csp_header
@@ -315,6 +361,34 @@ module Web
315
361
  end
316
362
  ```
317
363
 
364
+ and in `config/boot.rb`:
365
+
366
+ ```ruby
367
+ def before_load
368
+ ::SecureHeaders::Configuration.configure do |config|
369
+ config.hsts = {:max_age => 99, :include_subdomains => true}
370
+ config.x_frame_options = 'DENY'
371
+ config.x_content_type_options = "nosniff"
372
+ config.x_xss_protection = {:value => '1', :mode => false}
373
+ config.x_download_options = 'noopen'
374
+ config.x_permitted_cross_domain_policies = 'none'
375
+ config.csp = {
376
+ :default_src => "https: inline eval",
377
+ :report_uri => '//example.com/uri-directive',
378
+ :img_src => "https: data:",
379
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com"
380
+ }
381
+ end
382
+ end
383
+ ```
384
+
385
+ ## Similar libraries
386
+
387
+ * Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
388
+ * J2EE Servlet >= 3.0 [highlines](https://github.com/sourceclear/headlines)
389
+ * ASP.NET - [NWebsec](http://nwebsec.codeplex.com/)
390
+ * Python - [django-csp](https://github.com/mozilla/django-csp/) + [commonware](https://github.com/jsocol/commonware/)
391
+ * Go - [secureheader](https://github.com/kr/secureheader)
318
392
 
319
393
  ## Authors
320
394
 
@@ -330,6 +404,6 @@ end
330
404
 
331
405
  ## License
332
406
 
333
- Copyright 2013 Twitter, Inc.
407
+ Copyright 2013-2014 Twitter, Inc and other contributors.
334
408
 
335
409
  Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0