Skip to content

Commit 01f0091

Browse files
committed
Add trusted types directive
1 parent 7f89df2 commit 01f0091

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

lib/secure_headers/headers/content_security_policy_config.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def initialize(hash)
3535
@report_only = nil
3636
@report_uri = nil
3737
@require_sri_for = nil
38+
@require_trusted_types_for = nil
3839
@sandbox = nil
3940
@script_nonce = nil
4041
@script_src = nil
@@ -44,6 +45,7 @@ def initialize(hash)
4445
@style_src = nil
4546
@style_src_elem = nil
4647
@style_src_attr = nil
48+
@trusted_types = nil
4749
@worker_src = nil
4850
@upgrade_insecure_requests = nil
4951
@disable_nonce_backwards_compatibility = nil

lib/secure_headers/headers/policy_management.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "set"
4+
require 'byebug'
45

56
module SecureHeaders
67
module PolicyManagement
@@ -98,7 +99,19 @@ def self.included(base)
9899
STYLE_SRC_ATTR
99100
].flatten.freeze
100101

101-
ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0).uniq.sort
102+
# Experimental directives - these vary greatly in support
103+
# See MDN for details.
104+
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
105+
TRUSTED_TYPES = :trusted_types
106+
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-trusted-types-for
107+
REQUIRE_TRUSTED_TYPES_FOR = :require_trusted_types_for
108+
109+
DIRECTIVES_EXPERIMENTAL = [
110+
TRUSTED_TYPES,
111+
REQUIRE_TRUSTED_TYPES_FOR,
112+
].flatten.freeze
113+
114+
ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0 + DIRECTIVES_EXPERIMENTAL).uniq.sort
102115

103116
# Think of default-src and report-uri as the beginning and end respectively,
104117
# everything else is in between.
@@ -121,6 +134,7 @@ def self.included(base)
121134
OBJECT_SRC => :source_list,
122135
PLUGIN_TYPES => :media_type_list,
123136
REQUIRE_SRI_FOR => :require_sri_for_list,
137+
REQUIRE_TRUSTED_TYPES_FOR => :require_trusted_types_for_list,
124138
REPORT_URI => :source_list,
125139
PREFETCH_SRC => :source_list,
126140
SANDBOX => :sandbox_list,
@@ -130,6 +144,7 @@ def self.included(base)
130144
STYLE_SRC => :source_list,
131145
STYLE_SRC_ELEM => :source_list,
132146
STYLE_SRC_ATTR => :source_list,
147+
TRUSTED_TYPES => :source_list,
133148
WORKER_SRC => :source_list,
134149
UPGRADE_INSECURE_REQUESTS => :boolean,
135150
}.freeze
@@ -175,6 +190,7 @@ def self.included(base)
175190
].freeze
176191

177192
REQUIRE_SRI_FOR_VALUES = Set.new(%w(script style))
193+
REQUIRE_TRUSTED_TYPES_FOR_VALUES = Set.new(%w(script))
178194

179195
module ClassMethods
180196
# Public: generate a header name, value array that is user-agent-aware.
@@ -324,6 +340,8 @@ def validate_directive!(directive, value)
324340
validate_media_type_expression!(directive, value)
325341
when :require_sri_for_list
326342
validate_require_sri_source_expression!(directive, value)
343+
when :require_trusted_types_for_list
344+
validate_require_trusted_types_for_source_expression!(directive, value)
327345
else
328346
raise ContentSecurityPolicyConfigError.new("Unknown directive #{directive}")
329347
end
@@ -368,6 +386,16 @@ def validate_require_sri_source_expression!(directive, require_sri_for_expressio
368386
end
369387
end
370388

389+
# Private: validates that a require trusted types for expression:
390+
# 1. is an array of strings
391+
# 2. is a subset of ["script"]
392+
def validate_require_trusted_types_for_source_expression!(directive, require_trusted_types_for_expression)
393+
ensure_array_of_strings!(directive, require_trusted_types_for_expression)
394+
unless require_trusted_types_for_expression.to_set.subset?(REQUIRE_TRUSTED_TYPES_FOR_VALUES)
395+
raise ContentSecurityPolicyConfigError.new(%(require-sri for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression}))
396+
end
397+
end
398+
371399
# Private: validates that a source expression:
372400
# 1. is an array of strings
373401
# 2. does not contain any deprecated, now invalid values (inline, eval, self, none)

spec/lib/secure_headers/headers/content_security_policy_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ module SecureHeaders
141141
expect(csp.value).to eq("default-src 'self'; require-sri-for script style")
142142
end
143143

144+
it "supports require-trusted-types-for directive" do
145+
csp = ContentSecurityPolicy.new({require_trusted_types_for: %(script)})
146+
expect(csp.value).to eq("require-trusted-types-for script")
147+
end
148+
149+
it "does not support style for require-trusted-types-for directive" do
150+
expect { ContentSecurityPolicy.new({require_trusted_types_for: %(script style)}) }.to raise_error(ContentSecurityPolicyConfigError)
151+
end
152+
144153
it "includes prefetch-src" do
145154
csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com))
146155
expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com")
@@ -180,6 +189,11 @@ module SecureHeaders
180189
csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')})
181190
expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'")
182191
end
192+
193+
it "supports trusted-types directive" do
194+
csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)})
195+
expect(csp.value).to eq("trusted-types blahblahpolicy")
196+
end
183197
end
184198
end
185199
end

spec/lib/secure_headers/headers/policy_management_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ module SecureHeaders
4545
plugin_types: %w(application/x-shockwave-flash),
4646
prefetch_src: %w(fetch.com),
4747
require_sri_for: %w(script style),
48+
require_trusted_types_for: %w(script),
4849
script_src: %w('self'),
4950
style_src: %w('unsafe-inline'),
5051
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
@@ -53,6 +54,7 @@ module SecureHeaders
5354
script_src_attr: %w(example.com),
5455
style_src_elem: %w(example.com),
5556
style_src_attr: %w(example.com),
57+
trusted_types: %w(abcpolicy),
5658

5759
report_uri: %w(https://example.com/uri-directive),
5860
}

0 commit comments

Comments
 (0)