secure_headers 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -13
- data/lib/secure_headers/configuration.rb +1 -1
- data/lib/secure_headers/headers/clear_site_data.rb +4 -4
- data/lib/secure_headers/headers/content_security_policy.rb +2 -2
- data/lib/secure_headers/headers/content_security_policy_config.rb +2 -2
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -2
- data/lib/secure_headers/headers/policy_management.rb +2 -2
- data/lib/secure_headers/headers/referrer_policy.rb +1 -1
- data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
- data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
- data/lib/secure_headers/headers/x_download_options.rb +2 -2
- data/lib/secure_headers/headers/x_frame_options.rb +1 -1
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
- data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
- data/lib/secure_headers/railtie.rb +5 -5
- data/lib/secure_headers/version.rb +1 -1
- data/secure_headers.gemspec +13 -3
- metadata +14 -63
- data/.github/ISSUE_TEMPLATE.md +0 -41
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -20
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/build.yml +0 -25
- data/.github/workflows/github-release.yml +0 -28
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.rubocop.yml +0 -4
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -41
- data/Guardfile +0 -13
- data/Rakefile +0 -32
- data/docs/cookies.md +0 -65
- data/docs/hashes.md +0 -64
- data/docs/named_overrides_and_appends.md +0 -104
- data/docs/per_action_configuration.md +0 -139
- data/docs/sinatra.md +0 -25
- data/docs/upgrading-to-3-0.md +0 -42
- data/docs/upgrading-to-4-0.md +0 -35
- data/docs/upgrading-to-5-0.md +0 -15
- data/docs/upgrading-to-6-0.md +0 -50
- data/docs/upgrading-to-7-0.md +0 -12
- data/spec/lib/secure_headers/configuration_spec.rb +0 -121
- data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +0 -87
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +0 -215
- data/spec/lib/secure_headers/headers/cookie_spec.rb +0 -179
- data/spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb +0 -42
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +0 -265
- data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +0 -91
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +0 -33
- data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +0 -31
- data/spec/lib/secure_headers/headers/x_download_options_spec.rb +0 -29
- data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +0 -36
- data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +0 -48
- data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +0 -47
- data/spec/lib/secure_headers/middleware_spec.rb +0 -117
- data/spec/lib/secure_headers/view_helpers_spec.rb +0 -192
- data/spec/lib/secure_headers_spec.rb +0 -516
- data/spec/spec_helper.rb +0 -64
data/CONTRIBUTING.md
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
## Contributing
|
2
|
-
|
3
|
-
[fork]: https://github.com/twitter/secureheaders/fork
|
4
|
-
[pr]: https://github.com/twitter/secureheaders/compare
|
5
|
-
[style]: https://github.com/styleguide/ruby
|
6
|
-
[code-of-conduct]: CODE_OF_CONDUCT.md
|
7
|
-
|
8
|
-
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
|
9
|
-
|
10
|
-
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
11
|
-
|
12
|
-
## Submitting a pull request
|
13
|
-
|
14
|
-
0. [Fork][fork] and clone the repository
|
15
|
-
0. Configure and install the dependencies: `bundle install`
|
16
|
-
0. Make sure the tests pass on your machine: `bundle exec rspec spec`
|
17
|
-
0. Create a new branch: `git checkout -b my-branch-name`
|
18
|
-
0. Make your change, add tests, and make sure the tests still pass and that no warnings are raised
|
19
|
-
0. Push to your fork and [submit a pull request][pr]
|
20
|
-
0. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
21
|
-
|
22
|
-
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
23
|
-
|
24
|
-
- Write tests.
|
25
|
-
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
26
|
-
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
27
|
-
|
28
|
-
## Releasing
|
29
|
-
|
30
|
-
0. Ensure CI is green
|
31
|
-
0. Pull the latest code
|
32
|
-
0. Increment the version
|
33
|
-
0. Run `gem build secure_headers.gemspec`
|
34
|
-
0. Bump the Gemfile and Gemfile.lock versions for an app which relies on this gem
|
35
|
-
0. Test behavior locally, branch deploy, whatever needs to happen
|
36
|
-
0. Run `bundle exec rake release`
|
37
|
-
|
38
|
-
## Resources
|
39
|
-
|
40
|
-
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
41
|
-
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
data/Guardfile
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
guard :rspec, cmd: "bundle exec rspec", all_on_start: true, all_after_pass: true do
|
3
|
-
require "guard/rspec/dsl"
|
4
|
-
dsl = Guard::RSpec::Dsl.new(self)
|
5
|
-
|
6
|
-
# RSpec files
|
7
|
-
rspec = dsl.rspec
|
8
|
-
watch(rspec.spec_helper) { rspec.spec_dir }
|
9
|
-
watch(rspec.spec_support) { rspec.spec_dir }
|
10
|
-
watch(rspec.spec_files)
|
11
|
-
|
12
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
13
|
-
end
|
data/Rakefile
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
|
-
# frozen_string_literal: true
|
3
|
-
require "bundler/gem_tasks"
|
4
|
-
require "rspec/core/rake_task"
|
5
|
-
require "net/http"
|
6
|
-
require "net/https"
|
7
|
-
|
8
|
-
RSpec::Core::RakeTask.new
|
9
|
-
|
10
|
-
begin
|
11
|
-
require "rdoc/task"
|
12
|
-
rescue LoadError
|
13
|
-
require "rdoc/rdoc"
|
14
|
-
require "rake/rdoctask"
|
15
|
-
RDoc::Task = Rake::RDocTask
|
16
|
-
end
|
17
|
-
|
18
|
-
begin
|
19
|
-
require "rubocop/rake_task"
|
20
|
-
RuboCop::RakeTask.new
|
21
|
-
rescue LoadError
|
22
|
-
task(:rubocop) { $stderr.puts "RuboCop is disabled" }
|
23
|
-
end
|
24
|
-
|
25
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
26
|
-
rdoc.rdoc_dir = "rdoc"
|
27
|
-
rdoc.title = "SecureHeaders"
|
28
|
-
rdoc.options << "--line-numbers"
|
29
|
-
rdoc.rdoc_files.include("lib/**/*.rb")
|
30
|
-
end
|
31
|
-
|
32
|
-
task default: [:spec, :rubocop]
|
data/docs/cookies.md
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
## Cookies
|
2
|
-
|
3
|
-
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.
|
4
|
-
|
5
|
-
__Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
|
6
|
-
|
7
|
-
#### Defaults
|
8
|
-
|
9
|
-
By default, all cookies will get both `Secure`, `HttpOnly`, and `SameSite=Lax`.
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
config.cookies = {
|
13
|
-
secure: true, # defaults to true but will be a no op on non-HTTPS requests
|
14
|
-
httponly: true, # defaults to true
|
15
|
-
samesite: { # defaults to set `SameSite=Lax`
|
16
|
-
lax: true
|
17
|
-
}
|
18
|
-
}
|
19
|
-
```
|
20
|
-
|
21
|
-
#### Boolean-based configuration
|
22
|
-
|
23
|
-
Boolean-based configuration is intended to globally enable or disable a specific cookie attribute. *Note: As of 4.0, you must use OPT_OUT rather than false to opt out of the defaults.*
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
config.cookies = {
|
27
|
-
secure: true, # mark all cookies as Secure
|
28
|
-
httponly: SecureHeaders::OPT_OUT, # do not mark any cookies as HttpOnly
|
29
|
-
}
|
30
|
-
```
|
31
|
-
|
32
|
-
#### Hash-based configuration
|
33
|
-
|
34
|
-
Hash-based configuration allows for fine-grained control.
|
35
|
-
|
36
|
-
```ruby
|
37
|
-
config.cookies = {
|
38
|
-
secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
|
39
|
-
httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
|
40
|
-
}
|
41
|
-
```
|
42
|
-
|
43
|
-
#### SameSite cookie configuration
|
44
|
-
|
45
|
-
SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
|
46
|
-
|
47
|
-
```ruby
|
48
|
-
config.cookies = {
|
49
|
-
samesite: {
|
50
|
-
strict: true # mark all cookies as SameSite=Strict
|
51
|
-
}
|
52
|
-
}
|
53
|
-
```
|
54
|
-
|
55
|
-
`Strict`, `Lax`, and `None` enforcement modes can also be specified using a Hash.
|
56
|
-
|
57
|
-
```ruby
|
58
|
-
config.cookies = {
|
59
|
-
samesite: {
|
60
|
-
strict: { only: ['session_id_duplicate'] },
|
61
|
-
lax: { only: ['_guest', '_rails_session', 'device_id'] },
|
62
|
-
none: { only: ['_tracking', 'saml_cookie', 'session_id'] },
|
63
|
-
}
|
64
|
-
}
|
65
|
-
```
|
data/docs/hashes.md
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
## Hash
|
2
|
-
|
3
|
-
`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`.
|
4
|
-
|
5
|
-
You can add hash sources directly to your policy :
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
::SecureHeaders::Configuration.default do |config|
|
9
|
-
config.csp = {
|
10
|
-
default_src: %w('self')
|
11
|
-
|
12
|
-
# this is a made up value but browsers will show the expected hash in the console.
|
13
|
-
script_src: %w(sha256-123456)
|
14
|
-
}
|
15
|
-
end
|
16
|
-
```
|
17
|
-
|
18
|
-
You can also use the automated inline script detection/collection/computation of hash source values in your app.
|
19
|
-
|
20
|
-
```bash
|
21
|
-
rake secure_headers:generate_hashes
|
22
|
-
```
|
23
|
-
|
24
|
-
This will generate a file (`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.
|
25
|
-
|
26
|
-
```yaml
|
27
|
-
---
|
28
|
-
scripts:
|
29
|
-
app/views/asdfs/index.html.erb:
|
30
|
-
- "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
|
31
|
-
styles:
|
32
|
-
app/views/asdfs/index.html.erb:
|
33
|
-
- "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
|
34
|
-
- "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
|
35
|
-
```
|
36
|
-
|
37
|
-
##### Helpers
|
38
|
-
|
39
|
-
**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.
|
40
|
-
|
41
|
-
```erb
|
42
|
-
<%= hashed_style_tag do %>
|
43
|
-
body {
|
44
|
-
background-color: black;
|
45
|
-
}
|
46
|
-
<% end %>
|
47
|
-
|
48
|
-
<%= hashed_style_tag do %>
|
49
|
-
body {
|
50
|
-
font-size: 30px;
|
51
|
-
font-color: green;
|
52
|
-
}
|
53
|
-
<% end %>
|
54
|
-
|
55
|
-
<%= hashed_javascript_tag do %>
|
56
|
-
console.log(1)
|
57
|
-
<% end %>
|
58
|
-
```
|
59
|
-
|
60
|
-
```
|
61
|
-
Content-Security-Policy: ...
|
62
|
-
script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
|
63
|
-
style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
|
64
|
-
```
|
@@ -1,104 +0,0 @@
|
|
1
|
-
## Named Appends
|
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. Reusing a configuration name is not allowed and will throw an exception.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
def show
|
7
|
-
if include_widget?
|
8
|
-
@widget = widget.render
|
9
|
-
use_content_security_policy_named_append(:widget_partial)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
SecureHeaders::Configuration.named_append(:widget_partial) do |request|
|
15
|
-
SecureHeaders.override_x_frame_options(request, "DENY")
|
16
|
-
if request.controller_instance.current_user.in_test_bucket?
|
17
|
-
{ child_src: %w(beta.thirdpartyhost.com) }
|
18
|
-
else
|
19
|
-
{ child_src: %w(thirdpartyhost.com) }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
```
|
23
|
-
|
24
|
-
You can use as many named appends as you would like per request, but be careful because order of inclusion matters. Consider the following:
|
25
|
-
|
26
|
-
```ruby
|
27
|
-
SecureHeader::Configuration.default do |config|
|
28
|
-
config.csp = { default_src: %w('self')}
|
29
|
-
end
|
30
|
-
|
31
|
-
SecureHeaders::Configuration.named_append(:A) do |request|
|
32
|
-
{ default_src: %w(myhost.com) }
|
33
|
-
end
|
34
|
-
|
35
|
-
SecureHeaders::Configuration.named_append(:B) do |request|
|
36
|
-
{ script_src: %w('unsafe-eval') }
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
The following code will produce different policies due to the way policies are normalized (e.g. providing a previously undefined directive that inherits from `default-src`, removing host source values when `*` is provided. Removing `'none'` when additional values are present, etc.):
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
def index
|
44
|
-
use_content_security_policy_named_append(:A)
|
45
|
-
use_content_security_policy_named_append(:B)
|
46
|
-
# produces default-src 'self' myhost.com; script-src 'self' myhost.com 'unsafe-eval';
|
47
|
-
end
|
48
|
-
|
49
|
-
def show
|
50
|
-
use_content_security_policy_named_append(:B)
|
51
|
-
use_content_security_policy_named_append(:A)
|
52
|
-
# produces default-src 'self' myhost.com; script-src 'self' 'unsafe-eval';
|
53
|
-
end
|
54
|
-
```
|
55
|
-
|
56
|
-
|
57
|
-
## Named overrides
|
58
|
-
|
59
|
-
Named overrides serve two purposes:
|
60
|
-
|
61
|
-
* To be able to refer to a configuration by simple name.
|
62
|
-
* By precomputing the headers for a named configuration, the headers generated once and reused over every request.
|
63
|
-
|
64
|
-
To use a named override, drop a `SecureHeaders::Configuration.override` block **outside** of method definitions and then declare which named override you'd like to use. You can even override an override.
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
class ApplicationController < ActionController::Base
|
68
|
-
SecureHeaders::Configuration.default do |config|
|
69
|
-
config.csp = {
|
70
|
-
default_src: %w('self'),
|
71
|
-
script_src: %w(example.org)
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
|
-
# override default configuration
|
76
|
-
SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
|
77
|
-
config.csp[:script_src] << "otherdomain.com"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class MyController < ApplicationController
|
82
|
-
def index
|
83
|
-
# Produces default-src 'self'; script-src example.org otherdomain.com
|
84
|
-
use_secure_headers_override(:script_from_otherdomain_com)
|
85
|
-
end
|
86
|
-
|
87
|
-
def show
|
88
|
-
# Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
|
89
|
-
use_secure_headers_override(:another_config)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
```
|
93
|
-
|
94
|
-
Reusing a configuration name is not allowed and will throw an exception.
|
95
|
-
|
96
|
-
By default, a no-op configuration is provided. No headers will be set when this default override is used.
|
97
|
-
|
98
|
-
```ruby
|
99
|
-
class MyController < ApplicationController
|
100
|
-
def index
|
101
|
-
SecureHeaders.opt_out_of_all_protection(request)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
```
|
@@ -1,139 +0,0 @@
|
|
1
|
-
## Per-action configuration
|
2
|
-
|
3
|
-
You can override the settings for a given action by producing a temporary override. Be aware that because of the dynamic nature of the value, the header values will be computed per request.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
# Given a config of:
|
7
|
-
::SecureHeaders::Configuration.default do |config|
|
8
|
-
config.csp = {
|
9
|
-
default_src: %w('self'),
|
10
|
-
script_src: %w('self')
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
class MyController < ApplicationController
|
15
|
-
def index
|
16
|
-
# Append value to the source list, override 'none' values
|
17
|
-
# Produces: default-src 'self'; script-src 'self' s3.amazonaws.com; object-src 'self' www.youtube.com
|
18
|
-
append_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self' www.youtube.com))
|
19
|
-
|
20
|
-
# Overrides the previously set source list, override 'none' values
|
21
|
-
# Produces: default-src 'self'; script-src s3.amazonaws.com; object-src 'self'
|
22
|
-
override_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self'))
|
23
|
-
|
24
|
-
# Global settings default to "sameorigin"
|
25
|
-
override_x_frame_options("DENY")
|
26
|
-
end
|
27
|
-
```
|
28
|
-
|
29
|
-
The following methods are available as controller instance methods. They are also available as class methods, but require you to pass in the `request` object.
|
30
|
-
* `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
|
31
|
-
* `override_content_security_policy_directives(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
|
32
|
-
* `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
|
33
|
-
|
34
|
-
## Appending / overriding Content Security Policy
|
35
|
-
|
36
|
-
When manipulating content security policy, there are a few things to consider. The default header value is `default-src https:` which corresponds to a default configuration of `{ default_src: %w(https:)}`.
|
37
|
-
|
38
|
-
#### Append to the policy with a directive other than `default_src`
|
39
|
-
|
40
|
-
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:
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
::SecureHeaders::Configuration.default do |config|
|
44
|
-
config.csp = {
|
45
|
-
default_src: %w('self')
|
46
|
-
}
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
Code | Result
|
51
|
-
------------- | -------------
|
52
|
-
`append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
|
53
|
-
`override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
|
54
|
-
|
55
|
-
#### Nonce
|
56
|
-
|
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
|
-
|
59
|
-
```erb
|
60
|
-
<%= nonced_javascript_tag do %>
|
61
|
-
console.log("nonced!");
|
62
|
-
<% end %>
|
63
|
-
|
64
|
-
<%= nonced_style_tag do %>
|
65
|
-
body {
|
66
|
-
background-color: black;
|
67
|
-
}
|
68
|
-
<% end %>
|
69
|
-
|
70
|
-
<%= nonced_javascript_include_tag "include.js" %>
|
71
|
-
|
72
|
-
<%= nonced_javascript_pack_tag "pack.js" %>
|
73
|
-
|
74
|
-
<%= nonced_stylesheet_link_tag "link.css" %>
|
75
|
-
|
76
|
-
<%= nonced_stylesheet_pack_tag "pack.css" %>
|
77
|
-
```
|
78
|
-
|
79
|
-
becomes:
|
80
|
-
|
81
|
-
```html
|
82
|
-
<script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
|
83
|
-
console.log("nonced!")
|
84
|
-
</script>
|
85
|
-
<style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
|
86
|
-
body {
|
87
|
-
background-color: black;
|
88
|
-
}
|
89
|
-
</style>
|
90
|
-
```
|
91
|
-
|
92
|
-
```
|
93
|
-
|
94
|
-
Content-Security-Policy: ...
|
95
|
-
script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
|
96
|
-
style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
|
97
|
-
```
|
98
|
-
|
99
|
-
`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.
|
100
|
-
|
101
|
-
```erb
|
102
|
-
<script nonce="<%= content_security_policy_script_nonce %>">
|
103
|
-
console.log("whitelisted, will execute")
|
104
|
-
</script>
|
105
|
-
|
106
|
-
<script nonce="lol">
|
107
|
-
console.log("won't execute, not whitelisted")
|
108
|
-
</script>
|
109
|
-
|
110
|
-
<script>
|
111
|
-
console.log("won't execute, not whitelisted")
|
112
|
-
</script>
|
113
|
-
```
|
114
|
-
|
115
|
-
## Clearing browser cache
|
116
|
-
|
117
|
-
You can clear the browser cache after the logout request by using the following.
|
118
|
-
|
119
|
-
``` ruby
|
120
|
-
class ApplicationController < ActionController::Base
|
121
|
-
# Configuration override to send the Clear-Site-Data header.
|
122
|
-
SecureHeaders::Configuration.override(:clear_browser_cache) do |config|
|
123
|
-
config.clear_site_data = SecureHeaders::ClearSiteData::ALL_TYPES
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
# Clears the browser's cache for browsers supporting the Clear-Site-Data
|
128
|
-
# header.
|
129
|
-
#
|
130
|
-
# Returns nothing.
|
131
|
-
def clear_browser_cache
|
132
|
-
SecureHeaders.use_secure_headers_override(request, :clear_browser_cache)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
class SessionsController < ApplicationController
|
137
|
-
after_action :clear_browser_cache, only: :destroy
|
138
|
-
end
|
139
|
-
```
|
data/docs/sinatra.md
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
## Sinatra
|
2
|
-
|
3
|
-
Here's an example using SecureHeaders for Sinatra applications:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
require 'rubygems'
|
7
|
-
require 'sinatra'
|
8
|
-
require 'haml'
|
9
|
-
require 'secure_headers'
|
10
|
-
|
11
|
-
use SecureHeaders::Middleware
|
12
|
-
|
13
|
-
SecureHeaders::Configuration.default do |config|
|
14
|
-
...
|
15
|
-
end
|
16
|
-
|
17
|
-
class Donkey < Sinatra::Application
|
18
|
-
set :root, APP_ROOT
|
19
|
-
|
20
|
-
get '/' do
|
21
|
-
SecureHeaders.override_x_frame_options(request, SecureHeaders::OPT_OUT)
|
22
|
-
haml :index
|
23
|
-
end
|
24
|
-
end
|
25
|
-
```
|
data/docs/upgrading-to-3-0.md
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
`secure_headers` 3.0 is a near-complete rewrite. It includes breaking changes and removes a lot of features that were either leftover from the days when the CSP standard was not fully adopted or were just downright confusing.
|
2
|
-
|
3
|
-
Changes
|
4
|
-
==
|
5
|
-
|
6
|
-
| What | < = 2.x | >= 3.0 |
|
7
|
-
| ---------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
8
|
-
| Global configuration | `SecureHeaders::Configuration.configure` block | `SecureHeaders::Configuration.default` block |
|
9
|
-
| All headers besides HPKP and CSP | Accept hashes as config values | Must be strings (validated during configuration) |
|
10
|
-
| CSP directive values | Accepted space delimited strings OR arrays of strings | Must be arrays of strings |
|
11
|
-
| CSP Nonce values in views | `@content_security_policy_nonce` | `content_security_policy_nonce(:script)` or `content_security_policy_nonce(:style)` |
|
12
|
-
| nonce is no longer a source expression | `config.csp = "'self' 'nonce'"` | Remove `'nonce'` from source expression and use [nonce helpers](https://github.com/twitter/secureheaders#nonce). |
|
13
|
-
| `self`/`none` source expressions | Could be `self` / `none` / `'self'` / `'none'` | Must be `'self'` or `'none'` |
|
14
|
-
| `inline` / `eval` source expressions | Could be `inline`, `eval`, `'unsafe-inline'`, or `'unsafe-eval'` | Must be `'unsafe-eval'` or `'unsafe-inline'` |
|
15
|
-
| Per-action configuration | Override [`def secure_header_options_for(header, options)`](https://github.com/twitter/secureheaders/commit/bb9ebc6c12a677aad29af8e0f08ffd1def56efec#diff-04c6e90faac2675aa89e2176d2eec7d8R111) | Use [named overrides](https://github.com/twitter/secureheaders#named-overrides) or [per-action helpers](https://github.com/twitter/secureheaders#per-action-configuration) |
|
16
|
-
| CSP/HPKP use `report_only` config that defaults to false | `enforce: false` | `report_only: false` |
|
17
|
-
| Schemes in source expressions | Schemes were not stripped | Schemes are stripped by default to discourage mixed content. Setting `preserve_schemes: true` will revert to previous behavior |
|
18
|
-
| Opting out of default configuration | `skip_before_filter :set_x_download_options_header` or `config.x_download_options = false` | Within default block: `config.x_download_options = SecureHeaders::OPT_OUT` |
|
19
|
-
|
20
|
-
Migrating to 3.x from <= 2.x
|
21
|
-
==
|
22
|
-
|
23
|
-
1. Convert all headers except for CSP/HPKP using hashes to string values. The values are validated at runtime and will provide guidance on misconfigured headers.
|
24
|
-
1. Convert all instances of `self`/`none`/`eval`/`inline` to the corresponding values in the above table.
|
25
|
-
1. Convert all CSP space-delimited directives to an array of strings.
|
26
|
-
1. Convert all `enforce: true|false` to `report_only: true|false`.
|
27
|
-
1. Remove `ensure_security_headers` from controllers (3.x uses a middleware instead).
|
28
|
-
|
29
|
-
Everything is terrible, why should I upgrade?
|
30
|
-
==
|
31
|
-
|
32
|
-
`secure_headers` <= 2.x built every header per request using a series of automatically included `before_filters`. This is horribly inefficient because:
|
33
|
-
|
34
|
-
1. `before_filters` are slow and adding 8 per request isn't great
|
35
|
-
1. We are rebuilding strings that may never change for every request
|
36
|
-
1. Errors in the request may mean that the headers never get set in the first place
|
37
|
-
|
38
|
-
`secure_headers` 3.x sets headers in rack middleware that runs once per request and uses configuration values passed via `request.env`. This is much more efficient and somewhat guarantees that headers will always be set. **The values for the headers are cached and reused per request**.
|
39
|
-
|
40
|
-
Also, there is a more flexible API for customizing content security policies / X-Frame-Options. In practice, none of the other headers need granular controls. One way of customizing headers per request is to use the helper methods. The only downside of this technique is that headers will be computed from scratch.
|
41
|
-
|
42
|
-
See the [README](README.md) for more information.
|
data/docs/upgrading-to-4-0.md
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
## script_src must be set
|
2
|
-
|
3
|
-
Not setting a `script_src` value means your policy falls back to whatever `default_src` (also required) is set to. This can be very dangerous and indicates the policy is too loose.
|
4
|
-
|
5
|
-
However, sometimes you really don't need a `script-src` e.g. API responses (`default-src 'none'`) so you can set `script_src: SecureHeaders::OPT_OUT` to work around this.
|
6
|
-
|
7
|
-
## Default Content Security Policy
|
8
|
-
|
9
|
-
The default CSP has changed to be more universal without sacrificing too much security.
|
10
|
-
|
11
|
-
* Flash/Java disabled by default
|
12
|
-
* `img-src` allows data: images and favicons (among others)
|
13
|
-
* `style-src` allows inline CSS by default (most find it impossible/impractical to remove inline content today)
|
14
|
-
* `form-action` (not governed by `default-src`, practically treated as `*`) is set to `'self'`
|
15
|
-
|
16
|
-
Previously, the default CSP was:
|
17
|
-
|
18
|
-
`Content-Security-Policy: default-src 'self'`
|
19
|
-
|
20
|
-
The new default policy is:
|
21
|
-
|
22
|
-
`default-src https:; form-action 'self'; img-src https: data: 'self'; object-src 'none'; script-src https:; style-src 'self' 'unsafe-inline' https:`
|
23
|
-
|
24
|
-
## CSP configuration
|
25
|
-
|
26
|
-
* Setting `report_only: true` in a CSP config will raise an error. Instead, set `csp_report_only`.
|
27
|
-
* Setting `frame_src` and `child_src` when values don't match will raise an error. Just use `frame_src`.
|
28
|
-
|
29
|
-
## config.secure_cookies removed
|
30
|
-
|
31
|
-
Use `config.cookies` instead.
|
32
|
-
|
33
|
-
## Supported ruby versions
|
34
|
-
|
35
|
-
We've dropped support for ruby versions <= 2.2. Sorry.
|
data/docs/upgrading-to-5-0.md
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
## All cookies default to secure/httponly/SameSite=Lax
|
2
|
-
|
3
|
-
By default, *all* cookies will be marked as `SameSite=lax`,`secure`, and `httponly`. To opt-out, supply `SecureHeaders::OPT_OUT` as the value for `SecureHeaders.cookies` or the individual configs. Setting these values to `false` will raise an error.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
# specific opt outs
|
7
|
-
config.cookies = {
|
8
|
-
secure: SecureHeaders::OPT_OUT,
|
9
|
-
httponly: SecureHeaders::OPT_OUT,
|
10
|
-
samesite: SecureHeaders::OPT_OUT,
|
11
|
-
}
|
12
|
-
|
13
|
-
# nuclear option, just make things work again
|
14
|
-
config.cookies = SecureHeaders::OPT_OUT
|
15
|
-
```
|
data/docs/upgrading-to-6-0.md
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
## Named overrides are now dynamically applied
|
2
|
-
|
3
|
-
The original implementation of name overrides worked by making a copy of the default policy, applying the overrides, and storing the result for later use. But, this lead to unexpected results if named overrides were combined with a dynamic policy change. If a change was made to the default configuration during a request, followed by a named override, the dynamic changes would be lost. To keep things consistent named overrides have been rewritten to work the same as named appends in that they always operate on the configuration for the current request. As an example:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
class ApplicationController < ActionController::Base
|
7
|
-
Configuration.default do |config|
|
8
|
-
config.x_frame_options = SecureHeaders::OPT_OUT
|
9
|
-
end
|
10
|
-
|
11
|
-
SecureHeaders::Configuration.override(:dynamic_override) do |config|
|
12
|
-
config.x_content_type_options = "nosniff"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class FooController < ApplicationController
|
17
|
-
def bar
|
18
|
-
# Dynamically update the default config for this request
|
19
|
-
override_x_frame_options("DENY")
|
20
|
-
append_content_security_policy_directives(frame_src: "3rdpartyprovider.com")
|
21
|
-
|
22
|
-
# Override everything, discard modifications above
|
23
|
-
use_secure_headers_override(:dynamic_override)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
```
|
27
|
-
|
28
|
-
Prior to 6.0.0, the response would NOT include a `X-Frame-Options` header since the named override would be a copy of the default configuration, but with `X-Content-Type-Options` set to `nosniff`. As of 6.0.0, the above code results in both `X-Frame-Options` set to `DENY` AND `X-Content-Type-Options` set to `nosniff`.
|
29
|
-
|
30
|
-
## `ContentSecurityPolicyConfig#merge` and `ContentSecurityPolicyReportOnlyConfig#merge` work more like `Hash#merge`
|
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 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
|
-
|
34
|
-
## `Configuration#get` has been removed
|
35
|
-
|
36
|
-
This method is not typically directly called by users of SecureHeaders. Given that named overrides are no longer statically stored, fetching them no longer makes sense.
|
37
|
-
|
38
|
-
## Configuration headers are no longer cached
|
39
|
-
|
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
|
-
|
42
|
-
## Calling the default configuration more than once will result in an Exception
|
43
|
-
|
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
|
-
|
46
|
-
## All user agent sniffing has been removed
|
47
|
-
|
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
|
-
|
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).
|
data/docs/upgrading-to-7-0.md
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
## X-Xss-Protection is set to 0 by default
|
2
|
-
|
3
|
-
Version 6 and below of `secure_headers` set the `X-Xss-Protection` to `1; mode=block` by default. This was done to protect against reflected XSS attacks. However, this header is no longer recommended (see https://github.com/github/secure_headers/issues/439 for more information).
|
4
|
-
|
5
|
-
If any functionality in your app depended on this header being set to the previous value, you will need to set it explicitly in your configuration.
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
# config/initializers/secure_headers.rb
|
9
|
-
SecureHeaders::Configuration.default do |config|
|
10
|
-
config.x_xss_protection = "1; mode=block"
|
11
|
-
end
|
12
|
-
```
|