Skip to content

Commit cc7b2b5

Browse files
committed
unconditionally send nonces and unsafe-inline when working with nonces
1 parent c7fc44c commit cc7b2b5

File tree

4 files changed

+14
-60
lines changed

4 files changed

+14
-60
lines changed

lib/secure_headers/headers/content_security_policy.rb

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,7 @@ def populate_nonces(directive, source_list)
212212
# unsafe-inline, this is more concise.
213213
def append_nonce(source_list, nonce)
214214
if nonce
215-
if nonces_supported?
216-
source_list << "'nonce-#{nonce}'"
217-
else
218-
source_list << UNSAFE_INLINE
219-
end
215+
source_list.push(*["'nonce-#{nonce}'", UNSAFE_INLINE])
220216
end
221217

222218
source_list
@@ -256,10 +252,6 @@ def supported_directives
256252
end
257253
end
258254

259-
def nonces_supported?
260-
@nonces_supported ||= self.class.nonces_supported?(@parsed_ua)
261-
end
262-
263255
def symbol_to_hyphen_case(sym)
264256
sym.to_s.tr("_", "-")
265257
end

lib/secure_headers/headers/policy_management.rb

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,6 @@ def validate_config!(config)
227227
end
228228
end
229229

230-
# Public: check if a user agent supports CSP nonces
231-
#
232-
# user_agent - a String or a UserAgent object
233-
def nonces_supported?(user_agent)
234-
user_agent = UserAgent.parse(user_agent) if user_agent.is_a?(String)
235-
MODERN_BROWSERS.include?(user_agent.browser) ||
236-
user_agent.browser == "Safari" && (user_agent.version || CSP::FALLBACK_VERSION) >= CSP::VERSION_10
237-
end
238-
239230
# Public: combine the values from two different configs.
240231
#
241232
# original - the main config

spec/lib/secure_headers/headers/content_security_policy_spec.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ module SecureHeaders
124124

125125
it "supports strict-dynamic" do
126126
csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456}, USER_AGENTS[:chrome])
127-
expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456'")
127+
expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456' 'unsafe-inline'")
128128
end
129129

130130
context "browser sniffing" do
@@ -143,44 +143,44 @@ module SecureHeaders
143143

144144
it "does not filter any directives for Chrome" do
145145
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:chrome])
146-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
146+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
147147
end
148148

149149
it "does not filter any directives for Opera" do
150150
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:opera])
151-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
151+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
152152
end
153153

154154
it "filters blocked-all-mixed-content, child-src, and plugin-types for firefox" do
155155
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox])
156-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
156+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
157157
end
158158

159159
it "filters blocked-all-mixed-content, frame-src, and plugin-types for firefox 46 and higher" do
160160
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox46])
161-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
161+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
162162
end
163163

164-
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, nonce sources, hash sources, and plugin-types for Edge" do
164+
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, hash sources, and plugin-types for Edge" do
165165
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:edge])
166-
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
166+
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
167167
end
168168

169-
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, nonce sources, hash sources, and plugin-types for safari" do
169+
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, hash sources, and plugin-types for safari" do
170170
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
171-
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
171+
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
172172
end
173173

174-
it "adds 'unsafe-inline', filters blocked-all-mixed-content, upgrade-insecure-requests, nonce sources, and hash sources for safari 10 and higher" do
174+
it "adds 'unsafe-inline', filters blocked-all-mixed-content, upgrade-insecure-requests, and hash sources for safari 10 and higher" do
175175
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari10])
176-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; report-uri report-uri.com")
176+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
177177
end
178178

179179
it "falls back to standard Firefox defaults when the useragent version is not present" do
180180
ua = USER_AGENTS[:firefox].dup
181181
allow(ua).to receive(:version).and_return(nil)
182182
policy = ContentSecurityPolicy.new(complex_opts, ua)
183-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
183+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
184184
end
185185
end
186186
end

spec/lib/secure_headers_spec.rb

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -265,21 +265,6 @@ module SecureHeaders
265265
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src https:; img-src data:; script-src 'self'")
266266
end
267267

268-
it "does not append a nonce when the browser does not support it" do
269-
Configuration.default do |config|
270-
config.csp = {
271-
default_src: %w('self'),
272-
script_src: %w(mycdn.com 'unsafe-inline'),
273-
style_src: %w('self')
274-
}
275-
end
276-
277-
safari_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:safari5]))
278-
SecureHeaders.content_security_policy_script_nonce(safari_request)
279-
hash = SecureHeaders.header_hash_for(safari_request)
280-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline'; style-src 'self'")
281-
end
282-
283268
it "appends a nonce to the script-src when used" do
284269
Configuration.default do |config|
285270
config.csp = {
@@ -297,21 +282,7 @@ module SecureHeaders
297282
SecureHeaders.content_security_policy_script_nonce(chrome_request)
298283

299284
hash = SecureHeaders.header_hash_for(chrome_request)
300-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'; style-src 'self'")
301-
end
302-
303-
it "uses a nonce for safari 10+" do
304-
Configuration.default do |config|
305-
config.csp = {
306-
default_src: %w('self'),
307-
script_src: %w(mycdn.com)
308-
}
309-
end
310-
311-
safari_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:safari10]))
312-
nonce = SecureHeaders.content_security_policy_script_nonce(safari_request)
313-
hash = SecureHeaders.header_hash_for(safari_request)
314-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'")
285+
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}' 'unsafe-inline'; style-src 'self'")
315286
end
316287

317288
it "does not support the deprecated `report_only: true` format" do

0 commit comments

Comments
 (0)