secure_headers 6.0.0 → 6.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/build.yml +24 -0
- data/.github/workflows/github-release.yml +28 -0
- data/.rubocop.yml +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +47 -1
- data/Gemfile +4 -1
- data/LICENSE +1 -1
- data/README.md +70 -30
- data/docs/cookies.md +5 -4
- data/docs/named_overrides_and_appends.md +3 -6
- data/docs/per_action_configuration.md +2 -4
- data/docs/upgrading-to-6-0.md +4 -4
- data/lib/secure_headers/configuration.rb +24 -16
- data/lib/secure_headers/headers/content_security_policy.rb +34 -41
- data/lib/secure_headers/headers/content_security_policy_config.rb +15 -48
- data/lib/secure_headers/headers/cookie.rb +9 -3
- data/lib/secure_headers/headers/policy_management.rb +92 -17
- data/lib/secure_headers/middleware.rb +0 -6
- data/lib/secure_headers/utils/cookies_config.rb +7 -5
- data/lib/secure_headers/version.rb +5 -0
- data/lib/secure_headers/view_helper.rb +11 -10
- data/lib/secure_headers.rb +3 -11
- data/lib/tasks/tasks.rake +6 -7
- data/secure_headers.gemspec +9 -5
- data/spec/lib/secure_headers/configuration_spec.rb +54 -0
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +98 -8
- data/spec/lib/secure_headers/headers/cookie_spec.rb +22 -25
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +29 -19
- data/spec/lib/secure_headers/middleware_spec.rb +0 -19
- data/spec/lib/secure_headers/view_helpers_spec.rb +5 -4
- data/spec/lib/secure_headers_spec.rb +0 -35
- data/spec/spec_helper.rb +10 -1
- metadata +13 -12
- data/.travis.yml +0 -29
- data/lib/secure_headers/headers/public_key_pins.rb +0 -81
- data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6919954e57f87c70a4fa42baa5285649bd7484ec6785894a2b461b6f52558f29
|
4
|
+
data.tar.gz: 710492a0e64a47f41f2b079e6d4799922aa05e51d017cacafcc20d77383815ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efd8e608dfeafc5d7e7fcd06274b0b8ed0c640744ab9d8113597bef916f31666cbf518b1dcd6869d7af42fbcbaf15a6a4cf8100b97fcbf52f5ba790e495e26c0
|
7
|
+
data.tar.gz: dcc504641e1c22b24a05c76534e2f8ba7a7fd5ff1b5f891eb467d23876c60900ef235d2dd4ba49af4352b23ffd1cd246c720aff79668244b6a10cec3aab8ed6f
|
@@ -0,0 +1,24 @@
|
|
1
|
+
name: Build + Test
|
2
|
+
on: [pull_request, push]
|
3
|
+
|
4
|
+
jobs:
|
5
|
+
build:
|
6
|
+
name: Build + Test
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: [ '2.6', '2.7', '3.0', '3.1', '3.2' ]
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v3
|
14
|
+
- name: Set up Ruby ${{ matrix.ruby }}
|
15
|
+
uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
- name: Build and test with Rake
|
19
|
+
run: |
|
20
|
+
gem install bundler
|
21
|
+
bundle install --jobs 4 --retry 3 --without guard
|
22
|
+
bundle exec rspec spec
|
23
|
+
bundle exec rubocop
|
24
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: GitHub Release
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v*
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
Publish:
|
10
|
+
permissions:
|
11
|
+
contents: write
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
14
|
+
steps:
|
15
|
+
- name: Calculate release name
|
16
|
+
run: |
|
17
|
+
GITHUB_REF=${{ github.ref }}
|
18
|
+
RELEASE_NAME=${GITHUB_REF#"refs/tags/"}
|
19
|
+
echo "RELEASE_NAME=${RELEASE_NAME}" >> $GITHUB_ENV
|
20
|
+
- name: Publish release
|
21
|
+
uses: actions/create-release@v1
|
22
|
+
env:
|
23
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
24
|
+
with:
|
25
|
+
tag_name: ${{ github.ref }}
|
26
|
+
release_name: ${{ env.RELEASE_NAME }}
|
27
|
+
draft: false
|
28
|
+
prerelease: false
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.1.1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,49 @@
|
|
1
|
+
## 6.5.0
|
2
|
+
|
3
|
+
- CSP: Remove source expression deduplication. (@lgarron) https://github.com/github/secure_headers/pull/499
|
4
|
+
|
5
|
+
## 6.4.0
|
6
|
+
|
7
|
+
- CSP: Add support for trusted-types, require-trusted-types-for directive (@JackMc): https://github.com/github/secure_headers/pull/486
|
8
|
+
|
9
|
+
## 6.3.4
|
10
|
+
|
11
|
+
- CSP: Do not deduplicate alternate schema source expressions (@keithamus): https://github.com/github/secure_headers/pull/478
|
12
|
+
|
13
|
+
## 6.3.3
|
14
|
+
|
15
|
+
Fix hash generation for indented helper methods (@rahearn)
|
16
|
+
|
17
|
+
## 6.3.2
|
18
|
+
|
19
|
+
Add support for style-src-attr, style-src-elem, script-src-attr, and script-src-elem directives (@ggalmazor)
|
20
|
+
|
21
|
+
## 6.3.1
|
22
|
+
|
23
|
+
Fixes deprecation warnings when running under ruby 2.7
|
24
|
+
|
25
|
+
## 6.3.0
|
26
|
+
|
27
|
+
Fixes newline injection issue
|
28
|
+
|
29
|
+
## 6.2.0
|
30
|
+
|
31
|
+
Fixes semicolon injection issue reported by @mvgijssel see https://github.com/twitter/secure_headers/issues/418
|
32
|
+
|
33
|
+
## 6.1.2
|
34
|
+
|
35
|
+
Adds the ability to specify `SameSite=none` with the same configurability as `Strict`/`Lax` in order to disable Chrome's soon-to-be-lax-by-default state.
|
36
|
+
|
37
|
+
## 6.1.1
|
38
|
+
|
39
|
+
Adds the ability to disable the automatically-appended `'unsafe-inline'` value when nonces are used #404 (@will)
|
40
|
+
|
41
|
+
## 6.1
|
42
|
+
|
43
|
+
Adds support for navigate-to, prefetch-src, and require-sri-for #395
|
44
|
+
|
45
|
+
NOTE: this version is a breaking change due to the removal of HPKP. Remove the HPKP config, the standard is dead. Apologies for not doing a proper deprecate/major rev cycle :pray:
|
46
|
+
|
1
47
|
## 6.0
|
2
48
|
|
3
49
|
- See the [upgrading to 6.0](docs/upgrading-to-6-0.md) guide for the breaking changes.
|
@@ -350,7 +396,7 @@ Adds `upgrade-insecure-requests` support for requests from Firefox and Chrome (a
|
|
350
396
|
|
351
397
|
## 3.0.0
|
352
398
|
|
353
|
-
secure_headers 3.0.0 is a near-complete, not-entirely-backward-compatible rewrite. Please see the [upgrade guide](https://github.com/twitter/secureheaders/blob/
|
399
|
+
secure_headers 3.0.0 is a near-complete, not-entirely-backward-compatible rewrite. Please see the [upgrade guide](https://github.com/twitter/secureheaders/blob/main/docs/upgrading-to-3-0.md) for an in-depth explanation of the changes and the suggested upgrade path.
|
354
400
|
|
355
401
|
## 2.5.1 - 2016-02-16 18:11:11 UTC - Remove noisy deprecation warning
|
356
402
|
|
data/Gemfile
CHANGED
@@ -3,6 +3,8 @@ source "https://rubygems.org"
|
|
3
3
|
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem "benchmark-ips"
|
7
|
+
|
6
8
|
group :test do
|
7
9
|
gem "coveralls"
|
8
10
|
gem "json"
|
@@ -11,13 +13,14 @@ group :test do
|
|
11
13
|
gem "rspec"
|
12
14
|
gem "rubocop"
|
13
15
|
gem "rubocop-github"
|
16
|
+
gem "rubocop-performance"
|
14
17
|
gem "term-ansicolor"
|
15
18
|
gem "tins"
|
16
19
|
end
|
17
20
|
|
18
21
|
group :guard do
|
19
22
|
gem "growl"
|
20
|
-
gem "guard-rspec", platforms: [:
|
23
|
+
gem "guard-rspec", platforms: [:ruby]
|
21
24
|
gem "rb-fsevent"
|
22
25
|
gem "terminal-notifier-guard"
|
23
26
|
end
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright 2013, 2014, 2015, 2016, 2017 Twitter, Inc.
|
1
|
+
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Twitter, Inc.
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
4
|
|
data/README.md
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
# Secure Headers
|
1
|
+
# Secure Headers ![Build + Test](https://github.com/github/secure_headers/workflows/Build%20+%20Test/badge.svg?branch=main)
|
2
2
|
|
3
|
-
**
|
4
|
-
|
5
|
-
**The [3.x](https://github.com/twitter/secureheaders/tree/2.x) branch is moving into maintenance mode**. See the [upgrading to 3.x doc](docs/upgrading-to-3-0.md) for instructions on how to upgrade including the differences and benefits of using the 3.x branch.
|
6
|
-
|
7
|
-
**The [2.x branch](https://github.com/twitter/secureheaders/tree/2.x) will be not be maintained once 4.x is released**. The documentation below only applies to the 3.x branch. See the 2.x [README](https://github.com/twitter/secureheaders/blob/2.x/README.md) for the old way of doing things.
|
3
|
+
**main branch represents 6.x line**. See the [upgrading to 4.x doc](docs/upgrading-to-4-0.md), [upgrading to 5.x doc](docs/upgrading-to-5-0.md), or [upgrading to 6.x doc](docs/upgrading-to-6-0.md) for instructions on how to upgrade. Bug fixes should go in the 5.x branch for now.
|
8
4
|
|
9
5
|
The gem will automatically apply several headers that are related to security. This includes:
|
10
|
-
- Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](
|
6
|
+
- Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](https://www.w3.org/TR/CSP2/)
|
11
7
|
- https://csp.withgoogle.com
|
12
8
|
- https://csp.withgoogle.com/docs/strict-csp.html
|
13
9
|
- https://csp-evaluator.withgoogle.com
|
@@ -33,20 +29,6 @@ It can also mark all http cookies with the Secure, HttpOnly and SameSite attribu
|
|
33
29
|
- [Hashes](docs/hashes.md)
|
34
30
|
- [Sinatra Config](docs/sinatra.md)
|
35
31
|
|
36
|
-
## Getting Started
|
37
|
-
|
38
|
-
### Rails 3+
|
39
|
-
|
40
|
-
For Rails 3+ applications, `secure_headers` has a `railtie` that should automatically include the middleware. If for some reason the middleware is not being included follow the instructions for Rails 2.
|
41
|
-
|
42
|
-
### Rails 2
|
43
|
-
|
44
|
-
For Rails 2 or non-rails applications, an explicit statement is required to use the middleware component.
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
use SecureHeaders::Middleware
|
48
|
-
```
|
49
|
-
|
50
32
|
## Configuration
|
51
33
|
|
52
34
|
If you do not supply a `default` configuration, exceptions will be raised. If you would like to use a default configuration (which is fairly locked down), just call `SecureHeaders::Configuration.default` without any arguments or block.
|
@@ -75,11 +57,11 @@ SecureHeaders::Configuration.default do |config|
|
|
75
57
|
config.csp = {
|
76
58
|
# "meta" values. these will shape the header, but the values are not included in the header.
|
77
59
|
preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
|
60
|
+
disable_nonce_backwards_compatibility: true, # default: false. If false, `unsafe-inline` will be added automatically when using nonces. If true, it won't. See #403 for why you'd want this.
|
78
61
|
|
79
62
|
# directive values: these values will directly translate into source directives
|
80
63
|
default_src: %w('none'),
|
81
64
|
base_uri: %w('self'),
|
82
|
-
block_all_mixed_content: true, # see http://www.w3.org/TR/mixed-content/
|
83
65
|
child_src: %w('self'), # if child-src isn't supported, the value for frame-src will be set.
|
84
66
|
connect_src: %w(wss:),
|
85
67
|
font_src: %w('self' data:),
|
@@ -92,7 +74,11 @@ SecureHeaders::Configuration.default do |config|
|
|
92
74
|
sandbox: true, # true and [] will set a maximally restrictive setting
|
93
75
|
plugin_types: %w(application/x-shockwave-flash),
|
94
76
|
script_src: %w('self'),
|
77
|
+
script_src_elem: %w('self'),
|
78
|
+
script_src_attr: %w('self'),
|
95
79
|
style_src: %w('unsafe-inline'),
|
80
|
+
style_src_elem: %w('unsafe-inline'),
|
81
|
+
style_src_attr: %w('unsafe-inline'),
|
96
82
|
worker_src: %w('self'),
|
97
83
|
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
|
98
84
|
report_uri: %w(https://report-uri.io/example-csp)
|
@@ -105,6 +91,9 @@ SecureHeaders::Configuration.default do |config|
|
|
105
91
|
end
|
106
92
|
```
|
107
93
|
|
94
|
+
### Deprecated Configuration Values
|
95
|
+
* `block_all_mixed_content` - this value is deprecated in favor of `upgrade_insecure_requests`. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content for more information.
|
96
|
+
|
108
97
|
## Default values
|
109
98
|
|
110
99
|
All headers except for PublicKeyPins and ClearSiteData have a default value. The default set of headers is:
|
@@ -119,22 +108,73 @@ X-Permitted-Cross-Domain-Policies: none
|
|
119
108
|
X-Xss-Protection: 1; mode=block
|
120
109
|
```
|
121
110
|
|
111
|
+
## API configurations
|
112
|
+
|
113
|
+
Which headers you decide to use for API responses is entirely a personal choice. Things like X-Frame-Options seem to have no place in an API response and would be wasting bytes. While this is true, browsers can do funky things with non-html responses. At the minimum, we suggest CSP:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
SecureHeaders::Configuration.override(:api) do |config|
|
117
|
+
config.csp = { default_src: 'none' }
|
118
|
+
config.hsts = SecureHeaders::OPT_OUT
|
119
|
+
config.x_frame_options = SecureHeaders::OPT_OUT
|
120
|
+
config.x_content_type_options = SecureHeaders::OPT_OUT
|
121
|
+
config.x_xss_protection = SecureHeaders::OPT_OUT
|
122
|
+
config.x_permitted_cross_domain_policies = SecureHeaders::OPT_OUT
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
However, I would consider these headers anyways depending on your load and bandwidth requirements.
|
127
|
+
|
128
|
+
## Acknowledgements
|
129
|
+
|
130
|
+
This project originated within the Security team at Twitter. An archived fork from the point of transition is here: https://github.com/twitter-archive/secure_headers.
|
131
|
+
|
132
|
+
Contributors include:
|
133
|
+
* Neil Matatall @oreoshake
|
134
|
+
* Chris Aniszczyk
|
135
|
+
* Artur Dryomov
|
136
|
+
* Bjørn Mæland
|
137
|
+
* Arthur Chiu
|
138
|
+
* Jonathan Viney
|
139
|
+
* Jeffrey Horn
|
140
|
+
* David Collazo
|
141
|
+
* Brendon Murphy
|
142
|
+
* William Makley
|
143
|
+
* Reed Loden
|
144
|
+
* Noah Kantrowitz
|
145
|
+
* Wyatt Anderson
|
146
|
+
* Salimane Adjao Moustapha
|
147
|
+
* Francois Chagnon
|
148
|
+
* Jeff Hodges
|
149
|
+
* Ian Melven
|
150
|
+
* Darío Javier Cravero
|
151
|
+
* Logan Hasson
|
152
|
+
* Raul E Rangel
|
153
|
+
* Steve Agalloco
|
154
|
+
* Nate Collings
|
155
|
+
* Josh Kalderimis
|
156
|
+
* Alex Kwiatkowski
|
157
|
+
* Julich Mera
|
158
|
+
* Jesse Storimer
|
159
|
+
* Tom Daniels
|
160
|
+
* Kolja Dummann
|
161
|
+
* Jean-Philippe Doyle
|
162
|
+
* Blake Hitchcock
|
163
|
+
* vanderhoorn
|
164
|
+
* orthographic-pedant
|
165
|
+
* Narsimham Chelluri
|
166
|
+
|
167
|
+
If you've made a contribution and see your name missing from the list, make a PR and add it!
|
168
|
+
|
122
169
|
## Similar libraries
|
123
170
|
|
124
171
|
* Rack [rack-secure_headers](https://github.com/frodsan/rack-secure_headers)
|
125
172
|
* Node.js (express) [helmet](https://github.com/helmetjs/helmet) and [hood](https://github.com/seanmonstar/hood)
|
126
173
|
* Node.js (hapi) [blankie](https://github.com/nlf/blankie)
|
127
|
-
* J2EE Servlet >= 3.0 [headlines](https://github.com/sourceclear/headlines)
|
128
174
|
* ASP.NET - [NWebsec](https://github.com/NWebsec/NWebsec/wiki)
|
129
|
-
* Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security)
|
175
|
+
* Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security), [secure](https://github.com/TypeError/secure)
|
130
176
|
* Go - [secureheader](https://github.com/kr/secureheader)
|
131
177
|
* Elixir [secure_headers](https://github.com/anotherhale/secure_headers)
|
132
178
|
* Dropwizard [dropwizard-web-security](https://github.com/palantir/dropwizard-web-security)
|
133
179
|
* Ember.js [ember-cli-content-security-policy](https://github.com/rwjblue/ember-cli-content-security-policy/)
|
134
180
|
* PHP [secure-headers](https://github.com/BePsvPT/secure-headers)
|
135
|
-
|
136
|
-
## License
|
137
|
-
|
138
|
-
Copyright 2013-2014 Twitter, Inc and other contributors.
|
139
|
-
|
140
|
-
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
data/docs/cookies.md
CHANGED
@@ -25,7 +25,7 @@ Boolean-based configuration is intended to globally enable or disable a specific
|
|
25
25
|
```ruby
|
26
26
|
config.cookies = {
|
27
27
|
secure: true, # mark all cookies as Secure
|
28
|
-
httponly: OPT_OUT, # do not mark any cookies as HttpOnly
|
28
|
+
httponly: SecureHeaders::OPT_OUT, # do not mark any cookies as HttpOnly
|
29
29
|
}
|
30
30
|
```
|
31
31
|
|
@@ -52,13 +52,14 @@ config.cookies = {
|
|
52
52
|
}
|
53
53
|
```
|
54
54
|
|
55
|
-
`Strict` and `
|
55
|
+
`Strict`, `Lax`, and `None` enforcement modes can also be specified using a Hash.
|
56
56
|
|
57
57
|
```ruby
|
58
58
|
config.cookies = {
|
59
59
|
samesite: {
|
60
|
-
strict: { only: ['
|
61
|
-
lax: { only: ['_guest'] }
|
60
|
+
strict: { only: ['session_id_duplicate'] },
|
61
|
+
lax: { only: ['_guest', '_rails_session', 'device_id'] },
|
62
|
+
none: { only: ['_tracking', 'saml_cookie', 'session_id'] },
|
62
63
|
}
|
63
64
|
}
|
64
65
|
```
|
@@ -1,6 +1,6 @@
|
|
1
1
|
## Named Appends
|
2
2
|
|
3
|
-
Named Appends are blocks of code that can be reused and composed during requests. e.g. If a certain partial is rendered conditionally, and the csp needs to be adjusted for that partial, you can create a named append for that situation. The value returned by the block will be passed into `append_content_security_policy_directives`. The current request object is passed as an argument to the block for even more flexibility.
|
3
|
+
Named Appends are blocks of code that can be reused and composed during requests. e.g. If a certain partial is rendered conditionally, and the csp needs to be adjusted for that partial, you can create a named append for that situation. The value returned by the block will be passed into `append_content_security_policy_directives`. The current request object is passed as an argument to the block for even more flexibility. Reusing a configuration name is not allowed and will throw an exception.
|
4
4
|
|
5
5
|
```ruby
|
6
6
|
def show
|
@@ -76,11 +76,6 @@ class ApplicationController < ActionController::Base
|
|
76
76
|
SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
|
77
77
|
config.csp[:script_src] << "otherdomain.com"
|
78
78
|
end
|
79
|
-
|
80
|
-
# overrides the :script_from_otherdomain_com configuration
|
81
|
-
SecureHeaders::Configuration.override(:another_config, :script_from_otherdomain_com) do |config|
|
82
|
-
config.csp[:script_src] << "evenanotherdomain.com"
|
83
|
-
end
|
84
79
|
end
|
85
80
|
|
86
81
|
class MyController < ApplicationController
|
@@ -96,6 +91,8 @@ class MyController < ApplicationController
|
|
96
91
|
end
|
97
92
|
```
|
98
93
|
|
94
|
+
Reusing a configuration name is not allowed and will throw an exception.
|
95
|
+
|
99
96
|
By default, a no-op configuration is provided. No headers will be set when this default override is used.
|
100
97
|
|
101
98
|
```ruby
|
@@ -54,7 +54,7 @@ Code | Result
|
|
54
54
|
|
55
55
|
#### Nonce
|
56
56
|
|
57
|
-
You can use a view helper to automatically add nonces to script tags
|
57
|
+
You can use a view helper to automatically add nonces to script tags. Currently, using a nonce helper or calling `content_security_policy_nonce` will populate all configured CSP headers, including report-only and enforced policies.
|
58
58
|
|
59
59
|
```erb
|
60
60
|
<%= nonced_javascript_tag do %>
|
@@ -120,9 +120,7 @@ You can clear the browser cache after the logout request by using the following.
|
|
120
120
|
class ApplicationController < ActionController::Base
|
121
121
|
# Configuration override to send the Clear-Site-Data header.
|
122
122
|
SecureHeaders::Configuration.override(:clear_browser_cache) do |config|
|
123
|
-
config.clear_site_data =
|
124
|
-
SecureHeaders::ClearSiteData::ALL_TYPES
|
125
|
-
]
|
123
|
+
config.clear_site_data = SecureHeaders::ClearSiteData::ALL_TYPES
|
126
124
|
end
|
127
125
|
|
128
126
|
|
data/docs/upgrading-to-6-0.md
CHANGED
@@ -5,7 +5,7 @@ The original implementation of name overrides worked by making a copy of the def
|
|
5
5
|
```ruby
|
6
6
|
class ApplicationController < ActionController::Base
|
7
7
|
Configuration.default do |config|
|
8
|
-
config.x_frame_options = OPT_OUT
|
8
|
+
config.x_frame_options = SecureHeaders::OPT_OUT
|
9
9
|
end
|
10
10
|
|
11
11
|
SecureHeaders::Configuration.override(:dynamic_override) do |config|
|
@@ -29,7 +29,7 @@ Prior to 6.0.0, the response would NOT include a `X-Frame-Options` header since
|
|
29
29
|
|
30
30
|
## `ContentSecurityPolicyConfig#merge` and `ContentSecurityPolicyReportOnlyConfig#merge` work more like `Hash#merge`
|
31
31
|
|
32
|
-
These classes are typically not directly instantiated by users of SecureHeaders. But, if you access `config.csp` you end up accessing one of these objects. Prior to 6.0.0, `#merge` worked more like `#append` in that it would combine policies (i.e. if both policies contained the same key the values would be combined rather than overwritten). This was not consistent with `#merge!`, which worked more like
|
32
|
+
These classes are typically not directly instantiated by users of SecureHeaders. But, if you access `config.csp` you end up accessing one of these objects. Prior to 6.0.0, `#merge` worked more like `#append` in that it would combine policies (i.e. if both policies contained the same key the values would be combined rather than overwritten). This was not consistent with `#merge!`, which worked more like Ruby's `Hash#merge!` (overwriting duplicate keys). As of 6.0.0, `#merge` works the same as `#merge!`, but returns a new object instead of mutating `self`.
|
33
33
|
|
34
34
|
## `Configuration#get` has been removed
|
35
35
|
|
@@ -39,7 +39,7 @@ This method is not typically directly called by users of SecureHeaders. Given th
|
|
39
39
|
|
40
40
|
Prior to 6.0.0 SecureHeaders pre-built and cached the headers that corresponded to the default configuration. The same was also done for named overrides. However, now that named overrides are applied dynamically, those can no longer be cached. As a result, caching has been removed in the name of simplicity. Some micro-benchmarks indicate this shouldn't be a performance problem and will help to eliminate a class of bugs entirely.
|
41
41
|
|
42
|
-
##
|
42
|
+
## Calling the default configuration more than once will result in an Exception
|
43
43
|
|
44
44
|
Prior to 6.0.0 you could conceivably, though unlikely, have `Configure#default` called more than once. Because configurations are dynamic, configuring more than once could result in unexpected behavior. So, as of 6.0.0 we raise `AlreadyConfiguredError` if the default configuration is setup more than once.
|
45
45
|
|
@@ -47,4 +47,4 @@ Prior to 6.0.0 you could conceivably, though unlikely, have `Configure#default`
|
|
47
47
|
|
48
48
|
The policy configured is the policy that is delivered in terms of which directives are sent. We still dedup, strip schemes, and look for other optimizations but we will not e.g. conditionally send `frame-src` / `child-src` or apply `nonce`s / `unsafe-inline`.
|
49
49
|
|
50
|
-
The primary reason for these per-browser customization was to reduce console warnings. This has lead to many bugs and results
|
50
|
+
The primary reason for these per-browser customization was to reduce console warnings. This has lead to many bugs and results in confusing behavior. Also, console logs are incredibly noisy today and increasingly warn you about perfectly valid things (like sending `X-Frame-Options` and `frame-ancestors` together).
|
@@ -43,6 +43,9 @@ module SecureHeaders
|
|
43
43
|
def override(name, &block)
|
44
44
|
@overrides ||= {}
|
45
45
|
raise "Provide a configuration block" unless block_given?
|
46
|
+
if named_append_or_override_exists?(name)
|
47
|
+
raise AlreadyConfiguredError, "Configuration already exists"
|
48
|
+
end
|
46
49
|
@overrides[name] = block
|
47
50
|
end
|
48
51
|
|
@@ -59,6 +62,9 @@ module SecureHeaders
|
|
59
62
|
def named_append(name, &block)
|
60
63
|
@appends ||= {}
|
61
64
|
raise "Provide a configuration block" unless block_given?
|
65
|
+
if named_append_or_override_exists?(name)
|
66
|
+
raise AlreadyConfiguredError, "Configuration already exists"
|
67
|
+
end
|
62
68
|
@appends[name] = block
|
63
69
|
end
|
64
70
|
|
@@ -68,17 +74,26 @@ module SecureHeaders
|
|
68
74
|
|
69
75
|
private
|
70
76
|
|
77
|
+
def named_append_or_override_exists?(name)
|
78
|
+
(defined?(@appends) && @appends.key?(name)) ||
|
79
|
+
(defined?(@overrides) && @overrides.key?(name))
|
80
|
+
end
|
81
|
+
|
71
82
|
# Public: perform a basic deep dup. The shallow copy provided by dup/clone
|
72
83
|
# can lead to modifying parent objects.
|
73
84
|
def deep_copy(config)
|
74
85
|
return unless config
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
86
|
+
result = {}
|
87
|
+
config.each_pair do |key, value|
|
88
|
+
result[key] =
|
89
|
+
case value
|
90
|
+
when Array
|
91
|
+
value.dup
|
92
|
+
else
|
93
|
+
value
|
94
|
+
end
|
81
95
|
end
|
96
|
+
result
|
82
97
|
end
|
83
98
|
|
84
99
|
# Private: Returns the internal default configuration. This should only
|
@@ -115,7 +130,6 @@ module SecureHeaders
|
|
115
130
|
expect_certificate_transparency: ExpectCertificateTransparency,
|
116
131
|
csp: ContentSecurityPolicy,
|
117
132
|
csp_report_only: ContentSecurityPolicy,
|
118
|
-
hpkp: PublicKeyPins,
|
119
133
|
cookies: Cookie,
|
120
134
|
}.freeze
|
121
135
|
|
@@ -127,7 +141,9 @@ module SecureHeaders
|
|
127
141
|
# The list of attributes that must respond to a `make_header` method
|
128
142
|
HEADERABLE_ATTRIBUTES = (CONFIG_ATTRIBUTES - [:cookies]).freeze
|
129
143
|
|
130
|
-
|
144
|
+
attr_writer(*(CONFIG_ATTRIBUTES_TO_HEADER_CLASSES.reject { |key| [:csp, :csp_report_only].include?(key) }.keys))
|
145
|
+
|
146
|
+
attr_reader(*(CONFIG_ATTRIBUTES_TO_HEADER_CLASSES.keys))
|
131
147
|
|
132
148
|
@script_hashes = nil
|
133
149
|
@style_hashes = nil
|
@@ -144,7 +160,6 @@ module SecureHeaders
|
|
144
160
|
@clear_site_data = nil
|
145
161
|
@csp = nil
|
146
162
|
@csp_report_only = nil
|
147
|
-
@hpkp = nil
|
148
163
|
@hsts = nil
|
149
164
|
@x_content_type_options = nil
|
150
165
|
@x_download_options = nil
|
@@ -153,7 +168,6 @@ module SecureHeaders
|
|
153
168
|
@x_xss_protection = nil
|
154
169
|
@expect_certificate_transparency = nil
|
155
170
|
|
156
|
-
self.hpkp = OPT_OUT
|
157
171
|
self.referrer_policy = OPT_OUT
|
158
172
|
self.csp = ContentSecurityPolicyConfig.new(ContentSecurityPolicyConfig::DEFAULT)
|
159
173
|
self.csp_report_only = OPT_OUT
|
@@ -178,7 +192,6 @@ module SecureHeaders
|
|
178
192
|
copy.clear_site_data = @clear_site_data
|
179
193
|
copy.expect_certificate_transparency = @expect_certificate_transparency
|
180
194
|
copy.referrer_policy = @referrer_policy
|
181
|
-
copy.hpkp = @hpkp
|
182
195
|
copy
|
183
196
|
end
|
184
197
|
|
@@ -263,10 +276,5 @@ module SecureHeaders
|
|
263
276
|
raise ArgumentError, "Must provide either an existing CSP config or a CSP config hash"
|
264
277
|
end
|
265
278
|
end
|
266
|
-
|
267
|
-
def hpkp_report_host
|
268
|
-
return nil unless @hpkp && hpkp != OPT_OUT && @hpkp[:report_uri]
|
269
|
-
URI.parse(@hpkp[:report_uri]).host
|
270
|
-
end
|
271
279
|
end
|
272
280
|
end
|