New Upstream Snapshot - ruby-secure-headers
Ready changes
Summary
Merged new upstream version: 6.5.0+git20230103.1.accd05c (was: 6.3.2).
Resulting package
Built on 2023-01-05T12:08 (took 5m38s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-snapshots ruby-secure-headers
Lintian Result
Diff
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 8f7a894..0000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Feature Requests
-
-## Adding a new header
-
-Generally, adding a new header is always OK.
-
-* Is the header supported by any user agent? If so, which?
-* What does it do?
-* What are the valid values for the header?
-* Where does the specification live?
-
-## Adding a new CSP directive
-
-* Is the directive supported by any user agent? If so, which?
-* What does it do?
-* What are the valid values for the directive?
-
----
-
-# Bugs
-
-Console errors and deprecation warnings are considered bugs that should be addressed with more precise UA sniffing. Bugs caused by incorrect or invalid UA sniffing are also bugs.
-
-### Expected outcome
-
-Describe what you expected to happen
-
-1. I configure CSP to do X
-1. When I inspect the response headers, the CSP should have included X
-
-### Actual outcome
-
-1. The generated policy did not include X
-
-### Config
-
-Please provide the configuration (`SecureHeaders::Configuration.default`) you are using including any overrides (`SecureHeaders::Configuration.override`).
-
-### Generated headers
-
-Provide a sample response containing the headers
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index c151d88..0000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## All PRs:
-
-* [ ] Has tests
-* [ ] Documentation updated
-
-## Adding a new header
-
-Generally, adding a new header is always OK.
-
-* Is the header supported by any user agent? If so, which?
-* What does it do?
-* What are the valid values for the header?
-* Where does the specification live?
-
-## Adding a new CSP directive
-
-* Is the directive supported by any user agent? If so, which?
-* What does it do?
-* What are the valid values for the directive?
-
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index dcd9cd0..0000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: Build + Test
-on: [pull_request]
-
-jobs:
- build:
- name: Build + Test
- runs-on: ubuntu-latest
- strategy:
- matrix:
- ruby: [ '2.4', '2.5', '2.6', '2.7' ]
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up Ruby ${{ matrix.ruby }}
- uses: actions/setup-ruby@v1
- with:
- ruby-version: ${{ matrix.ruby }}
- - name: Build and test with Rake
- run: |
- gem install bundler
- bundle install --jobs 4 --retry 3 --without guard
- bundle exec rspec spec
- bundle exec rubocop
-
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
deleted file mode 100644
index 319e847..0000000
--- a/.github/workflows/sync.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# This workflow ensures the "master" branch is always up-to-date with the
-# "main" branch (our default one)
-name: sync_main_branch
-on:
- push:
- branches: [ main ]
-jobs:
- catch_up:
- runs-on: ubuntu-latest
- steps:
- - name: Check out the repository
- uses: actions/checkout@v2
- with:
- fetch-depth: 0
- - name: Merge development into master, then push it
- run: |
- git pull
- git checkout master
- git merge main
- git push
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0b32062..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-*.gem
-*.DS_STORE
-*.rbc
-.bundle
-.config
-.yardoc
-*.log
-Gemfile.lock
-_yardoc
-coverage
-pkg
-rdoc
-spec/reports
diff --git a/.ruby-version b/.ruby-version
index 338a5b5..94ff29c 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.6.6
+3.1.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ebb4ca..662bdd1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+## 6.5.0
+
+- CSP: Remove source expression deduplication. (@lgarron) https://github.com/github/secure_headers/pull/499
+
+## 6.4.0
+
+- CSP: Add support for trusted-types, require-trusted-types-for directive (@JackMc): https://github.com/github/secure_headers/pull/486
+
+## 6.3.4
+
+- CSP: Do not deduplicate alternate schema source expressions (@keithamus): https://github.com/github/secure_headers/pull/478
+
+## 6.3.3
+
+Fix hash generation for indented helper methods (@rahearn)
+
## 6.3.2
Add support for style-src-attr, style-src-elem, script-src-attr, and script-src-elem directives (@ggalmazor)
diff --git a/Gemfile b/Gemfile
index a6b3e54..78cca83 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,7 +9,7 @@ group :test do
gem "pry-nav"
gem "rack"
gem "rspec"
- gem "rubocop", "< 0.68"
+ gem "rubocop"
gem "rubocop-github"
gem "rubocop-performance"
gem "term-ansicolor"
diff --git a/README.md b/README.md
index 4cc5706..b842cac 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
**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.
The gem will automatically apply several headers that are related to security. This includes:
-- Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](http://www.w3.org/TR/CSP2/)
+- Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](https://www.w3.org/TR/CSP2/)
- https://csp.withgoogle.com
- https://csp.withgoogle.com/docs/strict-csp.html
- https://csp-evaluator.withgoogle.com
@@ -62,7 +62,7 @@ SecureHeaders::Configuration.default do |config|
# directive values: these values will directly translate into source directives
default_src: %w('none'),
base_uri: %w('self'),
- block_all_mixed_content: true, # see http://www.w3.org/TR/mixed-content/
+ block_all_mixed_content: true, # see https://www.w3.org/TR/mixed-content/
child_src: %w('self'), # if child-src isn't supported, the value for frame-src will be set.
connect_src: %w(wss:),
font_src: %w('self' data:),
@@ -170,7 +170,7 @@ If you've made a contribution and see your name missing from the list, make a PR
* Node.js (express) [helmet](https://github.com/helmetjs/helmet) and [hood](https://github.com/seanmonstar/hood)
* Node.js (hapi) [blankie](https://github.com/nlf/blankie)
* ASP.NET - [NWebsec](https://github.com/NWebsec/NWebsec/wiki)
-* Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security)
+* 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)
* Go - [secureheader](https://github.com/kr/secureheader)
* Elixir [secure_headers](https://github.com/anotherhale/secure_headers)
* Dropwizard [dropwizard-web-security](https://github.com/palantir/dropwizard-web-security)
diff --git a/debian/changelog b/debian/changelog
index a15bffc..d1af0d6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-secure-headers (6.5.0+git20230103.1.accd05c-1) UNRELEASED; urgency=low
+
+ * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 05 Jan 2023 12:04:22 -0000
+
ruby-secure-headers (6.3.2-1) unstable; urgency=medium
* Team upload
diff --git a/debian/patches/01-require-securerandom.patch b/debian/patches/01-require-securerandom.patch
index 3a22f1e..27ba636 100644
--- a/debian/patches/01-require-securerandom.patch
+++ b/debian/patches/01-require-securerandom.patch
@@ -6,9 +6,11 @@ Forwarded: not-needed
Last-Update: 2017-06-02
---- a/spec/spec_helper.rb
-+++ b/spec/spec_helper.rb
-@@ -4,6 +4,7 @@
+Index: ruby-secure-headers.git/spec/spec_helper.rb
+===================================================================
+--- ruby-secure-headers.git.orig/spec/spec_helper.rb
++++ ruby-secure-headers.git/spec/spec_helper.rb
+@@ -4,6 +4,7 @@ require "rspec"
require "rack"
require "coveralls"
Coveralls.wear!
diff --git a/debian/patches/03-fix-library-path.patch b/debian/patches/03-fix-library-path.patch
index 725822b..37a6207 100644
--- a/debian/patches/03-fix-library-path.patch
+++ b/debian/patches/03-fix-library-path.patch
@@ -4,9 +4,11 @@ Author: Abhijith PA <abhijith@openmailbox.org>
Forwarded: not-needed
Last-Update: 2017-08-02
---- a/spec/spec_helper.rb
-+++ b/spec/spec_helper.rb
-@@ -6,7 +6,7 @@
+Index: ruby-secure-headers.git/spec/spec_helper.rb
+===================================================================
+--- ruby-secure-headers.git.orig/spec/spec_helper.rb
++++ ruby-secure-headers.git/spec/spec_helper.rb
+@@ -6,7 +6,7 @@ require "coveralls"
Coveralls.wear!
require 'securerandom'
diff --git a/docs/per_action_configuration.md b/docs/per_action_configuration.md
index c17a9e5..63716db 100644
--- a/docs/per_action_configuration.md
+++ b/docs/per_action_configuration.md
@@ -54,7 +54,7 @@ Code | Result
#### Nonce
-You can use a view helper to automatically add nonces to script tags:
+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.
```erb
<%= nonced_javascript_tag do %>
@@ -120,9 +120,7 @@ You can clear the browser cache after the logout request by using the following.
class ApplicationController < ActionController::Base
# Configuration override to send the Clear-Site-Data header.
SecureHeaders::Configuration.override(:clear_browser_cache) do |config|
- config.clear_site_data = [
- SecureHeaders::ClearSiteData::ALL_TYPES
- ]
+ config.clear_site_data = SecureHeaders::ClearSiteData::ALL_TYPES
end
diff --git a/lib/secure_headers/configuration.rb b/lib/secure_headers/configuration.rb
index 538365a..996ca74 100644
--- a/lib/secure_headers/configuration.rb
+++ b/lib/secure_headers/configuration.rb
@@ -84,11 +84,12 @@ module SecureHeaders
def deep_copy(config)
return unless config
config.each_with_object({}) do |(key, value), hash|
- hash[key] = if value.is_a?(Array)
- value.dup
- else
- value
- end
+ hash[key] =
+ if value.is_a?(Array)
+ value.dup
+ else
+ value
+ end
end
end
diff --git a/lib/secure_headers/headers/content_security_policy.rb b/lib/secure_headers/headers/content_security_policy.rb
index cb75050..566004b 100644
--- a/lib/secure_headers/headers/content_security_policy.rb
+++ b/lib/secure_headers/headers/content_security_policy.rb
@@ -7,17 +7,18 @@ module SecureHeaders
include PolicyManagement
def initialize(config = nil)
- @config = if config.is_a?(Hash)
- if config[:report_only]
- ContentSecurityPolicyReportOnlyConfig.new(config || DEFAULT_CONFIG)
+ @config =
+ if config.is_a?(Hash)
+ if config[:report_only]
+ ContentSecurityPolicyReportOnlyConfig.new(config || DEFAULT_CONFIG)
+ else
+ ContentSecurityPolicyConfig.new(config || DEFAULT_CONFIG)
+ end
+ elsif config.nil?
+ ContentSecurityPolicyConfig.new(DEFAULT_CONFIG)
else
- ContentSecurityPolicyConfig.new(config || DEFAULT_CONFIG)
+ config
end
- elsif config.nil?
- ContentSecurityPolicyConfig.new(DEFAULT_CONFIG)
- else
- config
- end
@preserve_schemes = @config.preserve_schemes
@script_nonce = @config.script_nonce
@@ -34,11 +35,12 @@ module SecureHeaders
##
# Return the value of the CSP header
def value
- @value ||= if @config
- build_value
- else
- DEFAULT_VALUE
- end
+ @value ||=
+ if @config
+ build_value
+ else
+ DEFAULT_VALUE
+ end
end
private
@@ -51,7 +53,9 @@ module SecureHeaders
def build_value
directives.map do |directive_name|
case DIRECTIVE_VALUE_TYPES[directive_name]
- when :source_list, :require_sri_for_list # require_sri is a simple set of strings that don't need to deal with symbol casing
+ when :source_list,
+ :require_sri_for_list, # require_sri is a simple set of strings that don't need to deal with symbol casing
+ :require_trusted_types_for_list
build_source_list_directive(directive_name)
when :boolean
symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name)
@@ -129,7 +133,7 @@ module SecureHeaders
unless directive == REPORT_URI || @preserve_schemes
source_list = strip_source_schemes(source_list)
end
- dedup_source_list(source_list)
+ source_list.uniq
end
end
@@ -147,23 +151,6 @@ module SecureHeaders
end
end
- # Removes duplicates and sources that already match an existing wild card.
- #
- # e.g. *.github.com asdf.github.com becomes *.github.com
- def dedup_source_list(sources)
- sources = sources.uniq
- wild_sources = sources.select { |source| source =~ STAR_REGEXP }
-
- if wild_sources.any?
- sources.reject do |source|
- !wild_sources.include?(source) &&
- wild_sources.any? { |pattern| File.fnmatch(pattern, source) }
- end
- else
- sources
- end
- end
-
# Private: append a nonce to the script/style directories if script_nonce
# or style_nonce are provided.
def populate_nonces(directive, source_list)
diff --git a/lib/secure_headers/headers/content_security_policy_config.rb b/lib/secure_headers/headers/content_security_policy_config.rb
index 3c47716..5d3c755 100644
--- a/lib/secure_headers/headers/content_security_policy_config.rb
+++ b/lib/secure_headers/headers/content_security_policy_config.rb
@@ -35,6 +35,7 @@ module SecureHeaders
@report_only = nil
@report_uri = nil
@require_sri_for = nil
+ @require_trusted_types_for = nil
@sandbox = nil
@script_nonce = nil
@script_src = nil
@@ -44,6 +45,7 @@ module SecureHeaders
@style_src = nil
@style_src_elem = nil
@style_src_attr = nil
+ @trusted_types = nil
@worker_src = nil
@upgrade_insecure_requests = nil
@disable_nonce_backwards_compatibility = nil
diff --git a/lib/secure_headers/headers/cookie.rb b/lib/secure_headers/headers/cookie.rb
index 0ff045c..9d3f7cd 100644
--- a/lib/secure_headers/headers/cookie.rb
+++ b/lib/secure_headers/headers/cookie.rb
@@ -80,9 +80,9 @@ module SecureHeaders
end
def conditionally_flag?(configuration)
- if(Array(configuration[:only]).any? && (Array(configuration[:only]) & parsed_cookie.keys).any?)
+ if (Array(configuration[:only]).any? && (Array(configuration[:only]) & parsed_cookie.keys).any?)
true
- elsif(Array(configuration[:except]).any? && (Array(configuration[:except]) & parsed_cookie.keys).none?)
+ elsif (Array(configuration[:except]).any? && (Array(configuration[:except]) & parsed_cookie.keys).none?)
true
else
false
diff --git a/lib/secure_headers/headers/policy_management.rb b/lib/secure_headers/headers/policy_management.rb
index b81f3b0..1d464f4 100644
--- a/lib/secure_headers/headers/policy_management.rb
+++ b/lib/secure_headers/headers/policy_management.rb
@@ -98,7 +98,19 @@ module SecureHeaders
STYLE_SRC_ATTR
].flatten.freeze
- ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0).uniq.sort
+ # Experimental directives - these vary greatly in support
+ # See MDN for details.
+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
+ TRUSTED_TYPES = :trusted_types
+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-trusted-types-for
+ REQUIRE_TRUSTED_TYPES_FOR = :require_trusted_types_for
+
+ DIRECTIVES_EXPERIMENTAL = [
+ TRUSTED_TYPES,
+ REQUIRE_TRUSTED_TYPES_FOR,
+ ].flatten.freeze
+
+ ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0 + DIRECTIVES_EXPERIMENTAL).uniq.sort
# Think of default-src and report-uri as the beginning and end respectively,
# everything else is in between.
@@ -121,6 +133,7 @@ module SecureHeaders
OBJECT_SRC => :source_list,
PLUGIN_TYPES => :media_type_list,
REQUIRE_SRI_FOR => :require_sri_for_list,
+ REQUIRE_TRUSTED_TYPES_FOR => :require_trusted_types_for_list,
REPORT_URI => :source_list,
PREFETCH_SRC => :source_list,
SANDBOX => :sandbox_list,
@@ -130,6 +143,7 @@ module SecureHeaders
STYLE_SRC => :source_list,
STYLE_SRC_ELEM => :source_list,
STYLE_SRC_ATTR => :source_list,
+ TRUSTED_TYPES => :source_list,
WORKER_SRC => :source_list,
UPGRADE_INSECURE_REQUESTS => :boolean,
}.freeze
@@ -175,6 +189,7 @@ module SecureHeaders
].freeze
REQUIRE_SRI_FOR_VALUES = Set.new(%w(script style))
+ REQUIRE_TRUSTED_TYPES_FOR_VALUES = Set.new(%w('script'))
module ClassMethods
# Public: generate a header name, value array that is user-agent-aware.
@@ -270,7 +285,8 @@ module SecureHeaders
source_list?(directive) ||
sandbox_list?(directive) ||
media_type_list?(directive) ||
- require_sri_for_list?(directive)
+ require_sri_for_list?(directive) ||
+ require_trusted_types_for_list?(directive)
end
# For each directive in additions that does not exist in the original config,
@@ -278,11 +294,12 @@ module SecureHeaders
def populate_fetch_source_with_default!(original, additions)
# in case we would be appending to an empty directive, fill it with the default-src value
additions.each_key do |directive|
- directive = if directive.to_s.end_with?("_nonce")
- directive.to_s.gsub(/_nonce/, "_src").to_sym
- else
- directive
- end
+ directive =
+ if directive.to_s.end_with?("_nonce")
+ directive.to_s.gsub(/_nonce/, "_src").to_sym
+ else
+ directive
+ end
# Don't set a default if directive has an existing value
next if original[directive]
if FETCH_SOURCES.include?(directive)
@@ -307,6 +324,10 @@ module SecureHeaders
DIRECTIVE_VALUE_TYPES[directive] == :require_sri_for_list
end
+ def require_trusted_types_for_list?(directive)
+ DIRECTIVE_VALUE_TYPES[directive] == :require_trusted_types_for_list
+ end
+
# Private: Validates that the configuration has a valid type, or that it is a valid
# source expression.
def validate_directive!(directive, value)
@@ -324,6 +345,8 @@ module SecureHeaders
validate_media_type_expression!(directive, value)
when :require_sri_for_list
validate_require_sri_source_expression!(directive, value)
+ when :require_trusted_types_for_list
+ validate_require_trusted_types_for_source_expression!(directive, value)
else
raise ContentSecurityPolicyConfigError.new("Unknown directive #{directive}")
end
@@ -368,6 +391,16 @@ module SecureHeaders
end
end
+ # Private: validates that a require trusted types for expression:
+ # 1. is an array of strings
+ # 2. is a subset of ["'script'"]
+ def validate_require_trusted_types_for_source_expression!(directive, require_trusted_types_for_expression)
+ ensure_array_of_strings!(directive, require_trusted_types_for_expression)
+ unless require_trusted_types_for_expression.to_set.subset?(REQUIRE_TRUSTED_TYPES_FOR_VALUES)
+ raise ContentSecurityPolicyConfigError.new(%(require-trusted-types-for for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression}))
+ end
+ end
+
# Private: validates that a source expression:
# 1. is an array of strings
# 2. does not contain any deprecated, now invalid values (inline, eval, self, none)
diff --git a/lib/secure_headers/version.rb b/lib/secure_headers/version.rb
index 52b6f10..b65e0a0 100644
--- a/lib/secure_headers/version.rb
+++ b/lib/secure_headers/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module SecureHeaders
- VERSION = "6.3.2"
+ VERSION = "6.5.0"
end
diff --git a/lib/secure_headers/view_helper.rb b/lib/secure_headers/view_helper.rb
index 91eef4d..7ed5731 100644
--- a/lib/secure_headers/view_helper.rb
+++ b/lib/secure_headers/view_helper.rb
@@ -147,12 +147,13 @@ module SecureHeaders
def nonced_tag(type, content_or_options, block)
options = {}
- content = if block
- options = content_or_options
- capture(&block)
- else
- content_or_options.html_safe # :'(
- end
+ content =
+ if block
+ options = content_or_options
+ capture(&block)
+ else
+ content_or_options.html_safe # :'(
+ end
content_tag type, content, options.merge(nonce: _content_security_policy_nonce(type))
end
diff --git a/lib/tasks/tasks.rake b/lib/tasks/tasks.rake
index 374fea5..cb07824 100644
--- a/lib/tasks/tasks.rake
+++ b/lib/tasks/tasks.rake
@@ -20,10 +20,11 @@ namespace :secure_headers do
(is_erb?(filename) && inline_script =~ /<%.*%>/)
end
- def find_inline_content(filename, regex, hashes)
+ def find_inline_content(filename, regex, hashes, strip_trailing_whitespace)
file = File.read(filename)
file.scan(regex) do # TODO don't use gsub
inline_script = Regexp.last_match.captures.last
+ inline_script.gsub!(/(\r?\n)[\t ]+\z/, '\1') if strip_trailing_whitespace
if dynamic_content?(filename, inline_script)
puts "Looks like there's some dynamic content inside of a tag :-/"
puts "That pretty much means the hash value will never match."
@@ -38,9 +39,8 @@ namespace :secure_headers do
def generate_inline_script_hashes(filename)
hashes = []
- [INLINE_SCRIPT_REGEX, INLINE_HASH_SCRIPT_HELPER_REGEX].each do |regex|
- find_inline_content(filename, regex, hashes)
- end
+ find_inline_content(filename, INLINE_SCRIPT_REGEX, hashes, false)
+ find_inline_content(filename, INLINE_HASH_SCRIPT_HELPER_REGEX, hashes, true)
hashes
end
@@ -48,9 +48,8 @@ namespace :secure_headers do
def generate_inline_style_hashes(filename)
hashes = []
- [INLINE_STYLE_REGEX, INLINE_HASH_STYLE_HELPER_REGEX].each do |regex|
- find_inline_content(filename, regex, hashes)
- end
+ find_inline_content(filename, INLINE_STYLE_REGEX, hashes, false)
+ find_inline_content(filename, INLINE_HASH_STYLE_HELPER_REGEX, hashes, true)
hashes
end
diff --git a/secure_headers.gemspec b/secure_headers.gemspec
index c5f7292..4880c3f 100644
--- a/secure_headers.gemspec
+++ b/secure_headers.gemspec
@@ -9,12 +9,12 @@ Gem::Specification.new do |gem|
gem.version = SecureHeaders::VERSION
gem.authors = ["Neil Matatall"]
gem.email = ["neil.matatall@gmail.com"]
- gem.description = "Manages application of security headers with many safe defaults."
- gem.summary = 'Add easily configured security headers to responses
+ gem.summary = "Manages application of security headers with many safe defaults."
+ gem.description = 'Add easily configured security headers to responses
including content-security-policy, x-frame-options,
strict-transport-security, etc.'
gem.homepage = "https://github.com/twitter/secureheaders"
- gem.license = "Apache Public License 2.0"
+ gem.license = "MIT"
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
diff --git a/spec/lib/secure_headers/headers/content_security_policy_spec.rb b/spec/lib/secure_headers/headers/content_security_policy_spec.rb
index c080283..314b896 100644
--- a/spec/lib/secure_headers/headers/content_security_policy_spec.rb
+++ b/spec/lib/secure_headers/headers/content_security_policy_spec.rb
@@ -48,12 +48,12 @@ module SecureHeaders
expect(csp.value).to eq("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:")
end
- it "minifies source expressions based on overlapping wildcards" do
+ it "does not minify source expressions based on overlapping wildcards" do
config = {
default_src: %w(a.example.org b.example.org *.example.org https://*.example.org)
}
csp = ContentSecurityPolicy.new(config)
- expect(csp.value).to eq("default-src *.example.org")
+ expect(csp.value).to eq("default-src a.example.org b.example.org *.example.org")
end
it "removes http/s schemes from hosts" do
@@ -101,11 +101,21 @@ module SecureHeaders
expect(csp.value).to eq("default-src example.org; block-all-mixed-content")
end
- it "deduplicates any source expressions" do
- csp = ContentSecurityPolicy.new(default_src: %w(example.org example.org example.org))
+ it "handles wildcard subdomain with wildcard port" do
+ csp = ContentSecurityPolicy.new(default_src: %w(https://*.example.org:*))
+ expect(csp.value).to eq("default-src *.example.org:*")
+ end
+
+ it "deduplicates source expressions that match exactly (after scheme stripping)" do
+ csp = ContentSecurityPolicy.new(default_src: %w(example.org https://example.org example.org))
expect(csp.value).to eq("default-src example.org")
end
+ it "does not deduplicate non-matching schema source expressions" do
+ csp = ContentSecurityPolicy.new(default_src: %w(*.example.org wss://example.example.org))
+ expect(csp.value).to eq("default-src *.example.org wss://example.example.org")
+ end
+
it "creates maximally strict sandbox policy when passed no sandbox token values" do
csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: [])
expect(csp.value).to eq("default-src example.org; sandbox")
@@ -141,6 +151,11 @@ module SecureHeaders
expect(csp.value).to eq("default-src 'self'; require-sri-for script style")
end
+ it "allows style as a require-trusted-types-for source" do
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script))
+ expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script")
+ end
+
it "includes prefetch-src" do
csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com))
expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com")
@@ -180,6 +195,21 @@ module SecureHeaders
csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')})
expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'")
end
+
+ it "supports trusted-types directive" do
+ csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)})
+ expect(csp.value).to eq("trusted-types blahblahpolicy")
+ end
+
+ it "supports trusted-types directive with 'none'" do
+ csp = ContentSecurityPolicy.new({trusted_types: %w('none')})
+ expect(csp.value).to eq("trusted-types 'none'")
+ end
+
+ it "allows duplicate policy names in trusted-types directive" do
+ csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')})
+ expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'")
+ end
end
end
end
diff --git a/spec/lib/secure_headers/headers/policy_management_spec.rb b/spec/lib/secure_headers/headers/policy_management_spec.rb
index 1a9ac4e..0f7cf8a 100644
--- a/spec/lib/secure_headers/headers/policy_management_spec.rb
+++ b/spec/lib/secure_headers/headers/policy_management_spec.rb
@@ -45,6 +45,7 @@ module SecureHeaders
plugin_types: %w(application/x-shockwave-flash),
prefetch_src: %w(fetch.com),
require_sri_for: %w(script style),
+ require_trusted_types_for: %w('script'),
script_src: %w('self'),
style_src: %w('unsafe-inline'),
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
@@ -53,6 +54,7 @@ module SecureHeaders
script_src_attr: %w(example.com),
style_src_elem: %w(example.com),
style_src_attr: %w(example.com),
+ trusted_types: %w(abcpolicy),
report_uri: %w(https://example.com/uri-directive),
}
@@ -120,6 +122,12 @@ module SecureHeaders
end.to raise_error(ContentSecurityPolicyConfigError)
end
+ it "rejects style for trusted types" do
+ expect do
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(style_src: %w('self'), require_trusted_types_for: %w(script style), trusted_types: %w(abcpolicy))))
+ end
+ end
+
# this is mostly to ensure people don't use the antiquated shorthands common in other configs
it "performs light validation on source lists" do
expect do
diff --git a/spec/lib/secure_headers/view_helpers_spec.rb b/spec/lib/secure_headers/view_helpers_spec.rb
index c71534a..2a7f56e 100644
--- a/spec/lib/secure_headers/view_helpers_spec.rb
+++ b/spec/lib/secure_headers/view_helpers_spec.rb
@@ -6,7 +6,7 @@ class Message < ERB
include SecureHeaders::ViewHelpers
def self.template
-<<-TEMPLATE
+ <<-TEMPLATE
<% hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
console.log(1)
<% end %>
@@ -62,9 +62,10 @@ TEMPLATE
end
def content_tag(type, content = nil, options = nil, &block)
- content = if block_given?
- capture(block)
- end
+ content =
+ if block_given?
+ capture(block)
+ end
if options.is_a?(Hash)
options = options.map { |k, v| " #{k}=#{v}" }
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/configuration.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/hash_helper.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/clear_site_data.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/content_security_policy.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/content_security_policy_config.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/cookie.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/expect_certificate_transparency.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/policy_management.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/referrer_policy.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/strict_transport_security.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/x_content_type_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/x_download_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/x_frame_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/headers/x_xss_protection.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/middleware.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/railtie.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/utils/cookies_config.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/secure_headers/view_helper.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.5.0/lib/tasks/tasks.rake -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/secure_headers-6.5.0.gemspec
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/configuration.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/hash_helper.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/clear_site_data.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/content_security_policy.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/content_security_policy_config.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/cookie.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/expect_certificate_transparency.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/policy_management.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/referrer_policy.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/strict_transport_security.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/x_content_type_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/x_download_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/x_frame_options.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/headers/x_xss_protection.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/middleware.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/railtie.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/utils/cookies_config.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/version.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/secure_headers/view_helper.rb -rw-r--r-- root/root /usr/share/rubygems-integration/all/gems/secure_headers-6.3.2/lib/tasks/tasks.rake -rw-r--r-- root/root /usr/share/rubygems-integration/all/specifications/secure_headers-6.3.2.gemspec
No differences were encountered in the control files