secure_headers 3.0.3 → 3.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ce791545252f765e19db9b42b88d0dec3c7f14a
4
- data.tar.gz: 5a677c30789119f527ea04f940de663a98344339
3
+ metadata.gz: a02f16867ec55f8c168ace664cc63d760785256f
4
+ data.tar.gz: db54c113af8919984c8f382b957834f38210cf3e
5
5
  SHA512:
6
- metadata.gz: c861e7c69de1e69d4a53090a33b9c2f699900ee728d55694f0e7df7c32f430bebc65a9304cf0a8536c4663ed97c678340065a17a1ce6862c000b1c7984989d29
7
- data.tar.gz: cc33e4d244bbd8bdc46960594d5d6de0bae38bcac6b282f5be9a8a32807d6ad2eb737e28553335cc74223a8ede8c6d592207bd5ee168fb05bf91c04118c8ec69
6
+ metadata.gz: 6d9ddcb98a8c646d4e7a8cdb79bf3d8638cae4cb230ff268660e8eab7000fba99bb65e126ce55b3ff5f2a0346013fcf8b769dab4db697c82ab4461d444d0e2bd
7
+ data.tar.gz: b63c79ac3e9b37a4cff698f979f1ca6fd7e92567e35b1f9026be2e68a205e5badff302d512938a4d36517e8ec5b752d4833082e1b733ff73916fbf0b326641aa
data/.gitignore CHANGED
@@ -6,17 +6,8 @@
6
6
  .yardoc
7
7
  *.log
8
8
  Gemfile.lock
9
- InstalledFiles
10
9
  _yardoc
11
10
  coverage
12
- doc/
13
- lib/bundler/man
14
11
  pkg
15
12
  rdoc
16
13
  spec/reports
17
- test/tmp
18
- test/version_tmp
19
- *tmp
20
- *.sqlite3
21
- fixtures/rails_3_2_12_no_init/log
22
- fixtures/rails_3_2_12/log
data/.travis.yml CHANGED
@@ -1,13 +1,21 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - "2.2"
5
- - "2.1"
6
- - "2.0.0"
7
- - "1.9.3"
8
- - "jruby-19mode"
4
+ - ruby-head
5
+ - 2.2
6
+ - 2.1
7
+ - 2.0.0
8
+ - 1.9.3
9
+ - jruby-19mode
10
+ - jruby-head
11
+
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: jruby-head
15
+ - rvm: ruby-head
9
16
 
10
17
  before_install: gem update bundler
18
+ bundler_args: --without guard -j 3
11
19
 
12
20
  sudo: false
13
21
  cache: bundler
data/CHANGELOG.md CHANGED
@@ -1,3 +1,146 @@
1
+ ## 3.2.0 Cookie settings and CSP hash sources
2
+
3
+ ### Cookies
4
+
5
+ SecureHeaders supports `Secure`, `HttpOnly` and [`SameSite`](https://tools.ietf.org/html/draft-west-first-party-cookies-07) cookies. These can be defined in the form of a boolean, or as a Hash for more refined configuration.
6
+
7
+ __Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
8
+
9
+ #### Boolean-based configuration
10
+
11
+ Boolean-based configuration is intended to globally enable or disable a specific cookie attribute.
12
+
13
+ ```ruby
14
+ config.cookies = {
15
+ secure: true, # mark all cookies as Secure
16
+ httponly: false, # do not mark any cookies as HttpOnly
17
+ }
18
+ ```
19
+
20
+ #### Hash-based configuration
21
+
22
+ Hash-based configuration allows for fine-grained control.
23
+
24
+ ```ruby
25
+ config.cookies = {
26
+ secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
27
+ httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
28
+ }
29
+ ```
30
+
31
+ #### SameSite cookie configuration
32
+
33
+ SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
34
+
35
+ ```ruby
36
+ config.cookies = {
37
+ samesite: {
38
+ strict: true # mark all cookies as SameSite=Strict
39
+ }
40
+ }
41
+ ```
42
+
43
+ `Strict` and `Lax` enforcement modes can also be specified using a Hash.
44
+
45
+ ```ruby
46
+ config.cookies = {
47
+ samesite: {
48
+ strict: { only: ['_rails_session'] },
49
+ lax: { only: ['_guest'] }
50
+ }
51
+ }
52
+ ```
53
+
54
+ #### Hash
55
+
56
+ `script`/`style-src` hashes can be used to whitelist inline content that is static. This has the benefit of allowing inline content without opening up the possibility of dynamic javascript like you would with a `nonce`.
57
+
58
+ You can add hash sources directly to your policy :
59
+
60
+ ```ruby
61
+ ::SecureHeaders::Configuration.default do |config|
62
+ config.csp = {
63
+ default_src: %w('self')
64
+
65
+ # this is a made up value but browsers will show the expected hash in the console.
66
+ script_src: %w(sha256-123456)
67
+ }
68
+ end
69
+ ```
70
+
71
+ You can also use the automated inline script detection/collection/computation of hash source values in your app.
72
+
73
+ ```bash
74
+ rake secure_headers:generate_hashes
75
+ ```
76
+
77
+ This will generate a file (`config/config/secure_headers_generated_hashes.yml` by default, you can override by setting `ENV["secure_headers_generated_hashes_file"]`) containing a mapping of file names with the array of hash values found on that page. When ActionView renders a given file, we check if there are any known hashes for that given file. If so, they are added as values to the header.
78
+
79
+ ```yaml
80
+ ---
81
+ scripts:
82
+ app/views/asdfs/index.html.erb:
83
+ - "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
84
+ styles:
85
+ app/views/asdfs/index.html.erb:
86
+ - "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
87
+ - "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
88
+ ```
89
+
90
+ ##### Helpers
91
+
92
+ **This will not compute dynamic hashes** by design. The output of both helpers will be a plain `script`/`style` tag without modification and the known hashes for a given file will be added to `script-src`/`style-src` when `hashed_javascript_tag` and `hashed_style_tag` are used. You can use `raise_error_on_unrecognized_hash = true` to be extra paranoid that you have precomputed hash values for all of your inline content. By default, this will raise an error in non-production environments.
93
+
94
+ ```erb
95
+ <%= hashed_style_tag do %>
96
+ body {
97
+ background-color: black;
98
+ }
99
+ <% end %>
100
+
101
+ <%= hashed_style_tag do %>
102
+ body {
103
+ font-size: 30px;
104
+ font-color: green;
105
+ }
106
+ <% end %>
107
+
108
+ <%= hashed_javascript_tag do %>
109
+ console.log(1)
110
+ <% end %>
111
+ ```
112
+
113
+ ```
114
+ Content-Security-Policy: ...
115
+ script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
116
+ style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
117
+
118
+ ## 3.1.2 Bug fix for regression
119
+
120
+ See https://github.com/twitter/secureheaders/pull/239
121
+
122
+ This meant that when header caches were regenerated upon calling `SecureHeaders.override(:name)` and using it with `use_secure_headers_override` would result in default values for anything other than CSP/HPKP.
123
+
124
+ ## 3.1.1 Bug fix for regression
125
+
126
+ See https://github.com/twitter/secureheaders/pull/235
127
+
128
+ `idempotent_additions?` would return false when comparing `OPT_OUT` with `OPT_OUT`, causing `header_hash_for` to return a header cache with `{ nil => nil }` which cause the middleware to blow up when `{ nil => nil }` was merged into the rack header hash.
129
+
130
+ This is a regression in 3.1.0 only.
131
+
132
+ Now it returns true. I've added a test case to ensure that `header_hash_for` will never return such an element.
133
+
134
+ ## 3.1.0 Adding secure cookie support
135
+
136
+ New feature: marking all cookies as secure. Added by @jmera in https://github.com/twitter/secureheaders/pull/231. In the future, we'll probably add the ability to whitelist individual cookies that should not be marked secure. PRs welcome.
137
+
138
+ Internal refactoring: In https://github.com/twitter/secureheaders/pull/232, we changed the way dynamic CSP is handled internally. The biggest benefit is that highly dynamic policies (which can happen with multiple `append/override` calls per request) are handled better:
139
+
140
+ 1. Only the CSP header cache is busted when using a dynamic policy. All other headers are preserved and don't need to be generated. Dynamic X-Frame-Options changes modify the cache directly.
141
+ 1. Idempotency checks for policy modifications are deferred until the end of the request lifecycle and only happen once, instead of per `append/override` call. The idempotency check itself is fairly expensive itself.
142
+ 1. CSP header string is produced at most once per request.
143
+
1
144
  ## 3.0.3
2
145
 
3
146
  Bug fix for handling policy merges where appending a non-default source value (report-uri, plugin-types, frame-ancestors, base-uri, and form-action) would be combined with the default-src value. Appending a directive that doesn't exist in the current policy combines the new value with `default-src` to mimic the actual behavior of the addition. However, this does not make sense for non-default-src values (a.k.a. "fetch directives") and can lead to unexpected behavior like a `report-uri` value of `*`. Previously, this config:
@@ -14,6 +157,7 @@ When appending:
14
157
  {
15
158
  report_uri => %w(https://report-uri.io/asdf)
16
159
  }
160
+ ```
17
161
 
18
162
  Would result in `default-src *; report-uri *` which doesn't make any sense at all.
19
163
 
data/Gemfile CHANGED
@@ -6,9 +6,12 @@ group :test do
6
6
  gem "tins", "~> 1.6.0" # 1.7 requires ruby 2.0
7
7
  gem "pry-nav"
8
8
  gem "rack"
9
+ gem "rspec"
10
+ gem "coveralls"
11
+ end
12
+
13
+ group :guard do
9
14
  gem "guard-rspec", platforms: [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
10
- gem "rspec", ">= 3.1"
11
15
  gem "growl"
12
16
  gem "rb-fsevent"
13
- gem "coveralls", platforms: [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
14
17
  end
data/README.md CHANGED
@@ -15,6 +15,8 @@ The gem will automatically apply several headers that are related to security.
15
15
  - 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)
16
16
  - Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
17
17
 
18
+ It can also mark all http cookies with the Secure, HttpOnly and SameSite attributes (when configured to do so).
19
+
18
20
  `secure_headers` is a library with a global config, per request overrides, and rack middleware that enables you customize your application settings.
19
21
 
20
22
  ## Use
@@ -29,7 +31,14 @@ All `nil` values will fallback to their default values. `SecureHeaders::OPT_OUT`
29
31
 
30
32
  ```ruby
31
33
  SecureHeaders::Configuration.default do |config|
32
- config.hsts = "max-age=#{20.years.to_i}"
34
+ config.cookies = {
35
+ secure: true, # mark all cookies as "Secure"
36
+ httponly: true, # mark all cookies as "HttpOnly"
37
+ samesite: {
38
+ strict: true # mark all cookies as SameSite=Strict
39
+ }
40
+ }
41
+ config.hsts = "max-age=#{20.years.to_i}; includeSubdomains; preload"
33
42
  config.x_frame_options = "DENY"
34
43
  config.x_content_type_options = "nosniff"
35
44
  config.x_xss_protection = "1; mode=block"
@@ -57,13 +66,13 @@ SecureHeaders::Configuration.default do |config|
57
66
  plugin_types: %w(application/x-shockwave-flash),
58
67
  block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
59
68
  upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
60
- report_uri: %w(https://example.com/uri-directive)
69
+ report_uri: %w(https://report-uri.io/example-csp)
61
70
  }
62
71
  config.hpkp = {
63
72
  report_only: false,
64
73
  max_age: 60.days.to_i,
65
74
  include_subdomains: true,
66
- report_uri: "https://example.com/uri-directive",
75
+ report_uri: "https://report-uri.io/example-hpkp",
67
76
  pins: [
68
77
  {sha256: "abc"},
69
78
  {sha256: "123"}
@@ -175,7 +184,7 @@ When manipulating content security policy, there are a few things to consider. T
175
184
 
176
185
  #### Append to the policy with a directive other than `default_src`
177
186
 
178
- The value of `default_src` is joined with the addition. Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
187
+ The value of `default_src` is joined with the addition if the it is a [fetch directive](https://w3c.github.io/webappsec-csp/#directives-fetch). Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
179
188
 
180
189
  ```ruby
181
190
  ::SecureHeaders::Configuration.default do |config|
@@ -192,24 +201,6 @@ Code | Result
192
201
 
193
202
  #### Nonce
194
203
 
195
- script/style-nonce can be used to whitelist inline content. To do this, call the `SecureHeaders.content_security_policy_nonce` then set the nonce attributes on the various tags.
196
-
197
- 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.
198
-
199
- ```erb
200
- <script nonce="<%= content_security_policy_nonce %>">
201
- console.log("whitelisted, will execute")
202
- </script>
203
-
204
- <script nonce="lol">
205
- console.log("won't execute, not whitelisted")
206
- </script>
207
-
208
- <script>
209
- console.log("won't execute, not whitelisted")
210
- </script>
211
- ```
212
-
213
204
  You can use a view helper to automatically add nonces to script tags:
214
205
 
215
206
  ```erb
@@ -237,9 +228,93 @@ body {
237
228
  </style>
238
229
  ```
239
230
 
231
+ ```
232
+
233
+ Content-Security-Policy: ...
234
+ script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
235
+ style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
236
+ ```
237
+
238
+ `script`/`style-nonce` can be used to whitelist inline content. To do this, call the `content_security_policy_script_nonce` or `content_security_policy_style_nonce` then set the nonce attributes on the various tags.
239
+
240
+ ```erb
241
+ <script nonce="<%= content_security_policy_script_nonce %>">
242
+ console.log("whitelisted, will execute")
243
+ </script>
244
+
245
+ <script nonce="lol">
246
+ console.log("won't execute, not whitelisted")
247
+ </script>
248
+
249
+ <script>
250
+ console.log("won't execute, not whitelisted")
251
+ </script>
252
+ ```
253
+
240
254
  #### Hash
241
255
 
242
- The hash feature has been removed, for now.
256
+ `script`/`style-src` hashes can be used to whitelist inline content that is static. This has the benefit of allowing inline content without opening up the possibility of dynamic javascript like you would with a `nonce`.
257
+
258
+ You can add hash sources directly to your policy :
259
+
260
+ ```ruby
261
+ ::SecureHeaders::Configuration.default do |config|
262
+ config.csp = {
263
+ default_src: %w('self')
264
+
265
+ # this is a made up value but browsers will show the expected hash in the console.
266
+ script_src: %w(sha256-123456)
267
+ }
268
+ end
269
+ ```
270
+
271
+ You can also use the automated inline script detection/collection/computation of hash source values in your app.
272
+
273
+ ```bash
274
+ rake secure_headers:generate_hashes
275
+ ```
276
+
277
+ This will generate a file (`config/config/secure_headers_generated_hashes.yml` by default, you can override by setting `ENV["secure_headers_generated_hashes_file"]`) containing a mapping of file names with the array of hash values found on that page. When ActionView renders a given file, we check if there are any known hashes for that given file. If so, they are added as values to the header.
278
+
279
+ ```yaml
280
+ ---
281
+ scripts:
282
+ app/views/asdfs/index.html.erb:
283
+ - "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
284
+ styles:
285
+ app/views/asdfs/index.html.erb:
286
+ - "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
287
+ - "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
288
+ ```
289
+
290
+ ##### Helpers
291
+
292
+ **This will not compute dynamic hashes** by design. The output of both helpers will be a plain `script`/`style` tag without modification and the known hashes for a given file will be added to `script-src`/`style-src` when `hashed_javascript_tag` and `hashed_style_tag` are used. You can use `raise_error_on_unrecognized_hash = true` to be extra paranoid that you have precomputed hash values for all of your inline content. By default, this will raise an error in non-production environments.
293
+
294
+ ```erb
295
+ <%= hashed_style_tag do %>
296
+ body {
297
+ background-color: black;
298
+ }
299
+ <% end %>
300
+
301
+ <%= hashed_style_tag do %>
302
+ body {
303
+ font-size: 30px;
304
+ font-color: green;
305
+ }
306
+ <% end %>
307
+
308
+ <%= hashed_javascript_tag do %>
309
+ console.log(1)
310
+ <% end %>
311
+ ```
312
+
313
+ ```
314
+ Content-Security-Policy: ...
315
+ script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
316
+ style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
317
+ ```
243
318
 
244
319
  ### Public Key Pins
245
320
 
@@ -255,12 +330,63 @@ config.hpkp = {
255
330
  {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
256
331
  ],
257
332
  report_only: true, # defaults to false (report-only mode)
258
- report_uri: '//example.com/uri-directive',
333
+ report_uri: 'https://report-uri.io/example-hpkp',
259
334
  app_name: 'example',
260
335
  tag_report_uri: true
261
336
  }
262
337
  ```
263
338
 
339
+ ### Cookies
340
+
341
+ SecureHeaders supports `Secure`, `HttpOnly` and [`SameSite`](https://tools.ietf.org/html/draft-west-first-party-cookies-07) cookies. These can be defined in the form of a boolean, or as a Hash for more refined configuration.
342
+
343
+ __Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
344
+
345
+ #### Boolean-based configuration
346
+
347
+ Boolean-based configuration is intended to globally enable or disable a specific cookie attribute.
348
+
349
+ ```ruby
350
+ config.cookies = {
351
+ secure: true, # mark all cookies as Secure
352
+ httponly: false, # do not mark any cookies as HttpOnly
353
+ }
354
+ ```
355
+
356
+ #### Hash-based configuration
357
+
358
+ Hash-based configuration allows for fine-grained control.
359
+
360
+ ```ruby
361
+ config.cookies = {
362
+ secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
363
+ httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
364
+ }
365
+ ```
366
+
367
+ #### SameSite cookie configuration
368
+
369
+ SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
370
+
371
+ ```ruby
372
+ config.cookies = {
373
+ samesite: {
374
+ strict: true # mark all cookies as SameSite=Strict
375
+ }
376
+ }
377
+ ```
378
+
379
+ `Strict` and `Lax` enforcement modes can also be specified using a Hash.
380
+
381
+ ```ruby
382
+ config.cookies = {
383
+ samesite: {
384
+ strict: { only: ['_rails_session'] },
385
+ lax: { only: ['_guest'] }
386
+ }
387
+ }
388
+ ```
389
+
264
390
  ### Using with Sinatra
265
391
 
266
392
  Here's an example using SecureHeaders for Sinatra applications:
@@ -287,43 +413,6 @@ class Donkey < Sinatra::Application
287
413
  end
288
414
  ```
289
415
 
290
- ### Using with Padrino
291
-
292
- You can use SecureHeaders for Padrino applications as well:
293
-
294
- In your `Gemfile`:
295
-
296
- ```ruby
297
- gem "secure_headers", require: 'secure_headers'
298
- ```
299
-
300
- then in your `app.rb` file you can:
301
-
302
- ```ruby
303
- Padrino.use(SecureHeaders::Middleware)
304
- require 'secure_headers/padrino'
305
-
306
- module Web
307
- class App < Padrino::Application
308
- register SecureHeaders::Padrino
309
-
310
- get '/' do
311
- render 'index'
312
- end
313
- end
314
- end
315
- ```
316
-
317
- and in `config/boot.rb`:
318
-
319
- ```ruby
320
- def before_load
321
- SecureHeaders::Configuration.default do |config|
322
- ...
323
- end
324
- end
325
- ```
326
-
327
416
  ## Similar libraries
328
417
 
329
418
  * Rack [rack-secure_headers](https://github.com/frodsan/rack-secure_headers)
@@ -334,6 +423,8 @@ end
334
423
  * Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security)
335
424
  * Go - [secureheader](https://github.com/kr/secureheader)
336
425
  * Elixir [secure_headers](https://github.com/anotherhale/secure_headers)
426
+ * Dropwizard [dropwizard-web-security](https://github.com/palantir/dropwizard-web-security)
427
+ * Ember.js [ember-cli-content-security-policy](https://github.com/rwjblue/ember-cli-content-security-policy/)
337
428
 
338
429
  ## License
339
430