secure_headers 1.1.1 → 2.1.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 (128) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -8
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +8 -3
  6. data/Gemfile +6 -11
  7. data/README.md +219 -104
  8. data/Rakefile +11 -116
  9. data/fixtures/rails_3_2_12/Gemfile +0 -8
  10. data/fixtures/rails_3_2_12/app/controllers/things_controller.rb +0 -1
  11. data/fixtures/rails_3_2_12/app/views/layouts/application.html.erb +1 -4
  12. data/fixtures/rails_3_2_12/app/views/other_things/index.html.erb +2 -1
  13. data/fixtures/rails_3_2_12/app/views/things/index.html.erb +1 -21
  14. data/fixtures/rails_3_2_12/config/application.rb +0 -54
  15. data/fixtures/rails_3_2_12/config/environments/test.rb +2 -2
  16. data/fixtures/rails_3_2_12/config/initializers/secure_headers.rb +3 -1
  17. data/fixtures/rails_3_2_12/config/routes.rb +0 -57
  18. data/fixtures/rails_3_2_12/config/script_hashes.yml +5 -0
  19. data/fixtures/rails_3_2_12/config.ru +3 -0
  20. data/fixtures/rails_3_2_12/spec/controllers/other_things_controller_spec.rb +57 -19
  21. data/fixtures/rails_3_2_12/spec/controllers/things_controller_spec.rb +18 -13
  22. data/fixtures/rails_3_2_12/spec/spec_helper.rb +1 -5
  23. data/fixtures/rails_3_2_12_no_init/Gemfile +0 -9
  24. data/fixtures/rails_3_2_12_no_init/app/controllers/other_things_controller.rb +1 -2
  25. data/fixtures/rails_3_2_12_no_init/app/controllers/things_controller.rb +1 -1
  26. data/fixtures/rails_3_2_12_no_init/app/views/layouts/application.html.erb +0 -2
  27. data/fixtures/rails_3_2_12_no_init/app/views/things/index.html.erb +0 -21
  28. data/fixtures/rails_3_2_12_no_init/config/application.rb +0 -51
  29. data/fixtures/rails_3_2_12_no_init/config/environments/test.rb +2 -2
  30. data/fixtures/rails_3_2_12_no_init/config/routes.rb +0 -57
  31. data/fixtures/rails_3_2_12_no_init/spec/controllers/other_things_controller_spec.rb +17 -12
  32. data/fixtures/rails_3_2_12_no_init/spec/controllers/things_controller_spec.rb +17 -12
  33. data/fixtures/rails_3_2_12_no_init/spec/spec_helper.rb +3 -18
  34. data/fixtures/rails_4_1_8/Gemfile +5 -0
  35. data/fixtures/rails_4_1_8/README.rdoc +28 -0
  36. data/fixtures/rails_4_1_8/Rakefile +6 -0
  37. data/fixtures/rails_4_1_8/app/controllers/application_controller.rb +4 -0
  38. data/fixtures/rails_4_1_8/app/controllers/concerns/.keep +0 -0
  39. data/fixtures/rails_4_1_8/app/controllers/other_things_controller.rb +5 -0
  40. data/fixtures/rails_4_1_8/app/controllers/things_controller.rb +5 -0
  41. data/fixtures/rails_4_1_8/app/models/.keep +0 -0
  42. data/fixtures/rails_4_1_8/app/models/concerns/.keep +0 -0
  43. data/fixtures/rails_4_1_8/app/views/layouts/application.html.erb +11 -0
  44. data/fixtures/rails_4_1_8/app/views/other_things/index.html.erb +2 -0
  45. data/fixtures/rails_4_1_8/app/views/things/index.html.erb +1 -0
  46. data/fixtures/rails_4_1_8/config/application.rb +15 -0
  47. data/fixtures/rails_4_1_8/config/boot.rb +4 -0
  48. data/fixtures/rails_4_1_8/config/environment.rb +5 -0
  49. data/fixtures/rails_4_1_8/config/environments/test.rb +10 -0
  50. data/fixtures/rails_4_1_8/config/initializers/secure_headers.rb +17 -0
  51. data/fixtures/rails_4_1_8/config/routes.rb +4 -0
  52. data/fixtures/rails_4_1_8/config/script_hashes.yml +5 -0
  53. data/fixtures/rails_4_1_8/config/secrets.yml +22 -0
  54. data/fixtures/rails_4_1_8/config.ru +4 -0
  55. data/fixtures/rails_4_1_8/lib/assets/.keep +0 -0
  56. data/fixtures/rails_4_1_8/lib/tasks/.keep +0 -0
  57. data/fixtures/rails_4_1_8/log/.keep +0 -0
  58. data/fixtures/rails_4_1_8/spec/controllers/other_things_controller_spec.rb +83 -0
  59. data/fixtures/rails_4_1_8/spec/controllers/things_controller_spec.rb +59 -0
  60. data/fixtures/rails_4_1_8/spec/spec_helper.rb +15 -0
  61. data/fixtures/rails_4_1_8/vendor/assets/javascripts/.keep +0 -0
  62. data/fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep +0 -0
  63. data/lib/secure_headers/hash_helper.rb +7 -0
  64. data/lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb +22 -0
  65. data/lib/secure_headers/headers/content_security_policy.rb +160 -129
  66. data/lib/secure_headers/headers/public_key_pins.rb +95 -0
  67. data/lib/secure_headers/headers/strict_transport_security.rb +2 -1
  68. data/lib/secure_headers/headers/x_download_options.rb +39 -0
  69. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +40 -0
  70. data/lib/secure_headers/headers/x_xss_protection.rb +2 -1
  71. data/lib/secure_headers/padrino.rb +14 -0
  72. data/lib/secure_headers/railtie.rb +19 -24
  73. data/lib/secure_headers/version.rb +1 -1
  74. data/lib/secure_headers/view_helper.rb +68 -0
  75. data/lib/secure_headers.rb +78 -16
  76. data/lib/tasks/tasks.rake +48 -0
  77. data/secure_headers.gemspec +4 -4
  78. data/spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb +47 -0
  79. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +127 -220
  80. data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +37 -0
  81. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +21 -20
  82. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +12 -12
  83. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +32 -0
  84. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +12 -12
  85. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +64 -0
  86. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +20 -19
  87. data/spec/lib/secure_headers_spec.rb +115 -73
  88. data/spec/spec_helper.rb +30 -18
  89. metadata +62 -58
  90. data/.rvmrc +0 -1
  91. data/Guardfile +0 -10
  92. data/HISTORY.md +0 -115
  93. data/app/controllers/content_security_policy_controller.rb +0 -75
  94. data/config/curl-ca-bundle.crt +0 -5420
  95. data/config/routes.rb +0 -3
  96. data/fixtures/rails_3_2_12/Guardfile +0 -14
  97. data/fixtures/rails_3_2_12/app/models/thing.rb +0 -3
  98. data/fixtures/rails_3_2_12/config/database.yml +0 -25
  99. data/fixtures/rails_3_2_12/config/environments/development.rb +0 -37
  100. data/fixtures/rails_3_2_12/config/environments/production.rb +0 -67
  101. data/fixtures/rails_3_2_12/config/initializers/backtrace_silencers.rb +0 -7
  102. data/fixtures/rails_3_2_12/config/initializers/inflections.rb +0 -15
  103. data/fixtures/rails_3_2_12/config/initializers/mime_types.rb +0 -5
  104. data/fixtures/rails_3_2_12/config/initializers/secret_token.rb +0 -7
  105. data/fixtures/rails_3_2_12/config/initializers/session_store.rb +0 -8
  106. data/fixtures/rails_3_2_12/config/initializers/wrap_parameters.rb +0 -14
  107. data/fixtures/rails_3_2_12/config/locales/en.yml +0 -5
  108. data/fixtures/rails_3_2_12/db/schema.rb +0 -16
  109. data/fixtures/rails_3_2_12/db/seeds.rb +0 -7
  110. data/fixtures/rails_3_2_12_no_init/Guardfile +0 -14
  111. data/fixtures/rails_3_2_12_no_init/app/models/thing.rb +0 -3
  112. data/fixtures/rails_3_2_12_no_init/app/views/things/_form.html.erb +0 -17
  113. data/fixtures/rails_3_2_12_no_init/app/views/things/edit.html.erb +0 -6
  114. data/fixtures/rails_3_2_12_no_init/app/views/things/new.html.erb +0 -5
  115. data/fixtures/rails_3_2_12_no_init/app/views/things/show.html.erb +0 -5
  116. data/fixtures/rails_3_2_12_no_init/config/database.yml +0 -25
  117. data/fixtures/rails_3_2_12_no_init/config/environments/development.rb +0 -37
  118. data/fixtures/rails_3_2_12_no_init/config/environments/production.rb +0 -67
  119. data/fixtures/rails_3_2_12_no_init/config/initializers/backtrace_silencers.rb +0 -7
  120. data/fixtures/rails_3_2_12_no_init/config/initializers/inflections.rb +0 -15
  121. data/fixtures/rails_3_2_12_no_init/config/initializers/mime_types.rb +0 -5
  122. data/fixtures/rails_3_2_12_no_init/config/initializers/secret_token.rb +0 -7
  123. data/fixtures/rails_3_2_12_no_init/config/initializers/session_store.rb +0 -8
  124. data/fixtures/rails_3_2_12_no_init/config/initializers/wrap_parameters.rb +0 -14
  125. data/fixtures/rails_3_2_12_no_init/config/locales/en.yml +0 -5
  126. data/fixtures/rails_3_2_12_no_init/db/schema.rb +0 -16
  127. data/fixtures/rails_3_2_12_no_init/db/seeds.rb +0 -7
  128. data/spec/controllers/content_security_policy_controller_spec.rb +0 -90
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 16e634b2502cd5ee9d87fac9a9d2c6af9bc48fda
4
+ data.tar.gz: 1416e09703db75cdf25379a1273477f346080c72
5
+ SHA512:
6
+ metadata.gz: d1483f86c255f59593766bf3312d0085df5b59281c2daf426c16bf930c92c06ae17c17e07984be696b1719336e89ea7000e19948713b310354c749200e2debd6
7
+ data.tar.gz: eaf23b06c98757048b1516d87e429a23b5c70606db476f90eb042250bbd863bd1fddfdbcf12a6fce51e077a0ee3e6332cedcc041514de6a0ce55295d77a4bd65
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
+ 2.1.6
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,17 +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 'spork'
11
- gem 'pry'
12
- gem 'rspec'
13
- gem 'guard-spork', :platform => :ruby_19
14
- gem 'guard-rspec', :platform => :ruby_19
7
+ gem 'sqlite3', :platforms => [:ruby, :mswin, :mingw]
8
+ gem 'jdbc-sqlite3', :platforms => [:jruby]
9
+ gem 'rspec-rails', '>= 3.1'
10
+ gem 'rspec', '>= 3.1'
15
11
  gem 'growl'
16
12
  gem 'rb-fsevent'
17
- gem 'simplecov'
18
- gem 'debugger', :platform => :ruby_19
19
- gem 'ruby-debug', :platform => :ruby_18
13
+ gem 'coveralls', :platforms => [:ruby_19]
14
+ gem 'i18n', '< 0.7.0', :platforms => [:ruby_18]
20
15
  end
data/README.md CHANGED
@@ -1,41 +1,18 @@
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
- - 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)
4
+ - Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](http://www.w3.org/TR/CSP2/)
5
5
  - HTTP Strict Transport Security (HSTS) - Ensures the browser never visits the http version of a website. Protects from SSLStrip/Firesheep attacks. [HSTS Specification](https://tools.ietf.org/html/rfc6797)
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)
11
+ - Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorites. [Public Key Pinnning Specification](https://tools.ietf.org/html/draft-ietf-websec-key-pinning-21)
31
12
 
32
13
  ## Usage
33
14
 
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.
15
+ - `ensure_security_headers` in a controller will set security-related headers automatically based on the configuration below.
39
16
 
40
17
  ### Disabling
41
18
 
@@ -45,17 +22,18 @@ The following methods are going to be called, unless they are provided in a `ski
45
22
 
46
23
  * `:set_csp_header`
47
24
  * `:set_hsts_header`
25
+ * `:set_hpkp_header`
48
26
  * `:set_x_frame_options_header`
49
27
  * `:set_x_xss_protection_header`
50
28
  * `:set_x_content_type_options_header`
29
+ * `:set_x_download_options_header`
30
+ * `:set_x_permitted_cross_domain_policies_header`
51
31
 
52
32
  ### Bonus Features
53
33
 
54
34
  This gem makes a few assumptions about how you will use some features. For example:
55
35
 
56
36
  * 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.
57
- * 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.
58
-
59
37
 
60
38
  ## Configuration
61
39
 
@@ -67,27 +45,39 @@ This gem makes a few assumptions about how you will use some features. For exam
67
45
  config.x_frame_options = 'DENY'
68
46
  config.x_content_type_options = "nosniff"
69
47
  config.x_xss_protection = {:value => 1, :mode => 'block'}
48
+ config.x_download_options = 'noopen'
49
+ config.x_permitted_cross_domain_policies = 'none'
70
50
  config.csp = {
71
- :default_src => "https://* self",
72
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com",
73
- :img_src => "https://*",
51
+ :default_src => "https: self",
52
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com",
53
+ :img_src => "https:",
74
54
  :report_uri => '//example.com/uri-directive'
75
55
  }
56
+ config.hpkp = {
57
+ :max_age => 60.days.to_i,
58
+ :include_subdomains => true,
59
+ :report_uri => '//example.com/uri-directive',
60
+ :pins => [
61
+ {:sha256 => 'abc'},
62
+ {:sha256 => '123'}
63
+ ]
64
+ }
76
65
  end
77
66
 
78
- # and then simply include this in application_controller.rb
67
+ # and then include this in application_controller.rb
79
68
  class ApplicationController < ActionController::Base
80
69
  ensure_security_headers
81
70
  end
82
71
  ```
83
72
 
84
- Or simply add it to application controller
73
+ Or do the config as a parameter to `ensure_security_headers`
85
74
 
86
75
  ```ruby
87
76
  ensure_security_headers(
88
- :hsts => {:include_subdomains, :x_frame_options => false},
77
+ :hsts => {:include_subdomains => true, :max_age => 20.years.to_i},
89
78
  :x_frame_options => 'DENY',
90
- :csp => false)
79
+ :csp => false
80
+ )
91
81
  ```
92
82
 
93
83
  ## Options for ensure\_security\_headers
@@ -107,14 +97,12 @@ This configuration will likely work for most applications without modification.
107
97
  :x_frame_options => {:value => 'SAMEORIGIN'}
108
98
  :x_xss_protection => {:value => 1, :mode => 'block'} # set the :mode option to false to use "warning only" mode
109
99
  :x_content_type_options => {:value => 'nosniff'}
100
+ :x_download_options => {:value => 'noopen'}
101
+ :x_permitted_cross_domain_policies => {:value => 'none'}
110
102
  ```
111
103
 
112
104
  ### Content Security Policy (CSP)
113
105
 
114
- All browsers will receive the webkit csp header except Firefox, which gets its own header.
115
- See [WebKit specification](http://www.w3.org/TR/CSP/)
116
- and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specification)
117
-
118
106
  ```ruby
119
107
  :csp => {
120
108
  :enforce => false, # sets header to report-only, by default
@@ -124,11 +112,6 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
124
112
  # 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
125
113
  :report_uri => '//mysite.example.com',
126
114
 
127
- # Send reports that cannot be sent across host here. These requests are sent
128
- # the server, not the browser. If no value is supplied, it will default to
129
- # the value in report_uri. Use this if you cannot use relative protocols mentioned above due to host mismatches.
130
- :forward_endpoint => 'https://internal.mylogaggregator.example.com'
131
-
132
115
  # these directives all take 'none', 'self', or a globbed pattern
133
116
  :img_src => nil,
134
117
  :frame_src => nil,
@@ -143,32 +126,12 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
143
126
  # over http, relaxing the policy
144
127
  # e.g.
145
128
  # :csp => {
146
- # :img_src => 'https://*',
147
- # :http_additions => {:img_src => 'http//*'}
129
+ # :img_src => 'https:',
130
+ # :http_additions => {:img_src => 'http'}
148
131
  # }
149
- # would produce the directive: "img-src https://* http://*;"
132
+ # would produce the directive: "img-src https: http:;"
150
133
  # when over http, ignored for https requests
151
134
  :http_additions => {}
152
-
153
- # If you have enforce => true, you can use the `experiments` block to
154
- # also produce a report-only header. Values in this block override the
155
- # parent config for the report-only, and leave the enforcing header
156
- # unaltered. http_additions work the same way described above, but
157
- # are added to your report-only header as expected.
158
- :experimental => {
159
- :script_src => 'self',
160
- :img_src => 'https://mycdn.example.com',
161
- :http_additions {
162
- :img_src => 'http://mycdn.example.com'
163
- }
164
- }
165
-
166
- # script-nonce is an experimental feature of CSP 1.1 available in Chrome. It allows
167
- # you to whitelist inline script blocks. For more information, see
168
- # https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-nonce
169
- :script_nonce => lambda { @script_nonce = SecureRandom.hex }
170
- # which can be used to whitelist a script block:
171
- # script_tag :nonce = @script_nonce { inline_script_call() }
172
135
  }
173
136
  ```
174
137
 
@@ -178,19 +141,19 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
178
141
  ```ruby
179
142
  # most basic example
180
143
  :csp => {
181
- :default_src => "https://* inline eval",
144
+ :default_src => "https: inline eval",
182
145
  :report_uri => '/uri-directive'
183
146
  }
184
147
 
185
- > "default-src 'unsafe-inline' 'unsafe-eval' https://*; report-uri /uri-directive;"
148
+ > "default-src 'unsafe-inline' 'unsafe-eval' https:; report-uri /uri-directive;"
186
149
 
187
150
  # turn off inline scripting/eval
188
151
  :csp => {
189
- :default_src => 'https://*',
152
+ :default_src => 'https:',
190
153
  :report_uri => '/uri-directive'
191
154
  }
192
155
 
193
- > "default-src https://*; report-uri /uri-directive;"
156
+ > "default-src https:; report-uri /uri-directive;"
194
157
 
195
158
  # 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
196
159
  :csp => {
@@ -203,30 +166,169 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
203
166
  "default-src 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
204
167
  ```
205
168
 
206
- ## Note on Firefox handling of CSP
169
+ ### Tagging Requests
170
+
171
+ 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"
172
+
173
+ ```ruby
174
+ {
175
+ :tag_report_uri => true,
176
+ :enforce => true,
177
+ :app_name => 'twitter',
178
+ :report_uri => 'csp_reports'
179
+ }
180
+ ```
181
+
182
+ Results in
183
+ ```
184
+ report-uri csp_reports?enforce=true&app_name=twitter
185
+ ```
186
+
187
+ ### CSP Level 2 features
188
+
189
+ *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.*
190
+
191
+ #### Nonce
192
+
193
+ 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.
194
+
195
+ 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.
196
+
197
+ ```ruby
198
+ :csp => {
199
+ :default_src => 'self',
200
+ :script_src => 'self nonce'
201
+ }
202
+ ```
203
+
204
+ > content-security-policy: default-src 'self'; script-src 'self' 'nonce-abc123' 'unsafe-inline'
205
+
206
+ ```erb
207
+ <script nonce="<%= @content_security_policy_nonce %>">
208
+ console.log("whitelisted, will execute")
209
+ </script>
210
+
211
+ <script nonce="lol">
212
+ console.log("won't execute, not whitelisted")
213
+ </script>
214
+
215
+ <script>
216
+ console.log("won't execute, not whitelisted")
217
+ </script>
218
+ ```
219
+ You can use a view helper to automatically add nonces to script tags:
220
+ ```erb
221
+ <%= nonced_javascript_tag do %>
222
+ console.log("nonced!")
223
+ <% end %>
224
+ <%= nonced_javascript_tag("nonced without a block!") %>
225
+ ```
226
+
227
+ becomes:
207
228
 
208
- Currently, Firefox does not support the w3c draft standard. So there are a few steps taken to make the two interchangeable.
229
+ ```html
230
+ <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
231
+ console.log("nonced!")
232
+ </script>
233
+ ```
209
234
 
210
- * 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`
235
+ #### Hash
211
236
 
212
- ### Adding the Firefox report forwarding endpoint
237
+ 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.
213
238
 
214
- **You need to add the following line to the TOP of confib/routes.rb**
215
- **This is an unauthenticated, unauthorized endpoint. Only do this if your report\-uri is not on the same origin as your application!!!**
239
+ 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.
216
240
 
217
- #### Rails 2
241
+ If you only have a few hashes, you can hardcode them for the entire app:
218
242
 
219
243
  ```ruby
220
- map.csp_endpoint
244
+ config.csp = {
245
+ :default_src => "https:",
246
+ :script_src => 'self'
247
+ :script_hashes => ['sha1-abc', 'sha1-qwe']
248
+ }
221
249
  ```
222
250
 
223
- #### Rails 3
251
+ The following will work as well, but may not be as clear:
252
+
253
+ ```ruby
254
+ config.csp = {
255
+ :default_src => "https:",
256
+ :script_src => "self 'sha1-qwe'"
257
+ }
258
+ ```
224
259
 
225
- If the csp reporting endpoint is clobbered by another route, add:
260
+ 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:
226
261
 
227
262
  ```ruby
228
- post SecureHeaders::ContentSecurityPolicy::FF_CSP_ENDPOINT => "content_security_policy#scribe"
263
+ # config.ru
264
+ require 'secure_headers/headers/content_security_policy/script_hash_middleware'
265
+ use ::SecureHeaders::ContentSecurityPolicy::ScriptHashMiddleware
266
+ ```
267
+
268
+ ```ruby
269
+ config.csp = {
270
+ :default_src => "https:",
271
+ :script_src => 'self',
272
+ :script_hash_middleware => true
273
+ }
274
+ ```
275
+
276
+ 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:
277
+
278
+ ```$ bundle exec rake secure_headers:generate_hashes```
279
+
280
+ Which will generate something like:
281
+
282
+ ```yaml
283
+ # config/script_hashes.yml
284
+ app/views/layouts/application.html.erb:
285
+ - sha256-l8OLjZqYRnKilpdE0VosRMvhdYArjXT4NZaK2p7QVvs=
286
+ app/templates/articles/edit.html.erb:
287
+ - sha256-+7mij1/uCwtCQRWrof2NmOln5qX+5WdVwTLMpi8nuoA=
288
+ - sha256-Ny4TRIhhFpnYnSeKC274P6bfAz4TOkezLabavIAU4dA=
289
+ - sha256-I5e58Gqbu4WpO9dck18QxO7aYOHKrELIi70it4jIPi0=
290
+ - sha256-Po4LMynwnAJHxiTp3DQaQ3YDBj3paN/xrDoKl4OyxY4=
229
291
  ```
292
+
293
+ In this example, if we visit /articles/edit/[id], the above hashes will automatically be added to the CSP header's
294
+ script-src value!
295
+
296
+ You can use plain "script" tags or you can use a built-in helper:
297
+
298
+ ```erb
299
+ <%= hashed_javascript_tag do %>
300
+ console.log("hashed automatically!")
301
+ <% end %>
302
+ ```
303
+
304
+ 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:
305
+
306
+ ```erb
307
+ <%= hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
308
+ console.log("will raise an exception if not in script_hashes.yml!")
309
+ <% end %>
310
+ ```
311
+
312
+ ### Public Key Pins
313
+
314
+ Be aware that pinning error reporting is governed by the same rules as everything else. If you have a pinning failure that tries to report back to the same origin, by definition this will not work.
315
+
316
+ ```
317
+ config.hpkp = {
318
+ max_age: 60.days.to_i, # max_age is a required parameter
319
+ include_subdomains: true, # whether or not to apply pins to subdomains
320
+ # Per the spec, SHA256 hashes are the only currently supported format.
321
+ pins: [
322
+ {sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
323
+ {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
324
+ ],
325
+ enforce: true, # defaults to false (report-only mode)
326
+ report_uri: '//example.com/uri-directive',
327
+ app_name: 'example',
328
+ tag_report_uri: true
329
+ }
330
+ ```
331
+
230
332
  ### Using with Sinatra
231
333
 
232
334
  Here's an example using SecureHeaders for Sinatra applications:
@@ -242,12 +344,15 @@ require 'secure_headers'
242
344
  config.x_frame_options = 'DENY'
243
345
  config.x_content_type_options = "nosniff"
244
346
  config.x_xss_protection = {:value => 1, :mode => false}
347
+ config.x_download_options = 'noopen'
348
+ config.x_permitted_cross_domain_policies = 'none'
245
349
  config.csp = {
246
- :default_src => "https://* inline eval",
350
+ :default_src => "https: inline eval",
247
351
  :report_uri => '//example.com/uri-directive',
248
- :img_src => "https://* data:",
249
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
352
+ :img_src => "https: data:",
353
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com"
250
354
  }
355
+ config.hpkp = false
251
356
  end
252
357
 
253
358
  class Donkey < Sinatra::Application
@@ -274,22 +379,11 @@ In your `Gemfile`:
274
379
  then in your `app.rb` file you can:
275
380
 
276
381
  ```ruby
382
+ require 'secure_headers/padrino'
383
+
277
384
  module Web
278
385
  class App < Padrino::Application
279
- include SecureHeaders
280
-
281
- ::SecureHeaders::Configuration.configure do |config|
282
- config.hsts = {:max_age => 99, :include_subdomains => true}
283
- config.x_frame_options = 'DENY'
284
- config.x_content_type_options = "nosniff"
285
- config.x_xss_protection = {:value => '1', :mode => false}
286
- config.csp = {
287
- :default_src => "https://* inline eval",
288
- :report_uri => '//example.com/uri-directive',
289
- :img_src => "https://* data:",
290
- :frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
291
- }
292
- end
386
+ register SecureHeaders::Padrino
293
387
 
294
388
  get '/' do
295
389
  set_csp_header
@@ -299,12 +393,33 @@ module Web
299
393
  end
300
394
  ```
301
395
 
396
+ and in `config/boot.rb`:
397
+
398
+ ```ruby
399
+ def before_load
400
+ ::SecureHeaders::Configuration.configure do |config|
401
+ config.hsts = {:max_age => 99, :include_subdomains => true}
402
+ config.x_frame_options = 'DENY'
403
+ config.x_content_type_options = "nosniff"
404
+ config.x_xss_protection = {:value => '1', :mode => false}
405
+ config.x_download_options = 'noopen'
406
+ config.x_permitted_cross_domain_policies = 'none'
407
+ config.csp = {
408
+ :default_src => "https: inline eval",
409
+ :report_uri => '//example.com/uri-directive',
410
+ :img_src => "https: data:",
411
+ :frame_src => "https: http:.twimg.com http://itunes.apple.com"
412
+ }
413
+ end
414
+ end
415
+ ```
416
+
302
417
  ## Similar libraries
303
418
 
304
419
  * Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
305
420
  * J2EE Servlet >= 3.0 [highlines](https://github.com/sourceclear/headlines)
306
421
  * ASP.NET - [NWebsec](http://nwebsec.codeplex.com/)
307
- * Python - [django-csp](https://github.com/mozilla/django-csp/tree/master/csp) + [commonware](https://github.com/jsocol/commonware/tree/master/commonware/request)
422
+ * Python - [django-csp](https://github.com/mozilla/django-csp/) + [commonware](https://github.com/jsocol/commonware/)
308
423
  * Go - [secureheader](https://github.com/kr/secureheader)
309
424
 
310
425
  ## Authors
@@ -321,6 +436,6 @@ end
321
436
 
322
437
  ## License
323
438
 
324
- Copyright 2013 Twitter, Inc.
439
+ Copyright 2013-2014 Twitter, Inc and other contributors.
325
440
 
326
441
  Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0