Skip to content

Commit a8c6a22

Browse files
Copilotfletchto99
andcommitted
Don't set upgrade_insecure_requests for HTTP requests
Co-authored-by: fletchto99 <[email protected]>
1 parent 157440e commit a8c6a22

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ coverage
1111
pkg
1212
rdoc
1313
spec/reports
14+
vendor/bundle

lib/secure_headers.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def opt_out_of_all_protection(request)
133133
# request.
134134
#
135135
# StrictTransportSecurity is not applied to http requests.
136+
# upgrade_insecure_requests is not applied to http requests.
136137
# See #config_for to determine which config is used for a given request.
137138
#
138139
# Returns a hash of header names => header values. The value
@@ -146,6 +147,22 @@ def header_hash_for(request)
146147

147148
if request.scheme != HTTPS
148149
headers.delete(StrictTransportSecurity::HEADER_NAME)
150+
151+
# Remove upgrade_insecure_requests from CSP headers for HTTP requests
152+
# as it doesn't make sense to upgrade requests when the page itself is served over HTTP
153+
if !config.csp.opt_out? && config.csp.directive_value(ContentSecurityPolicy::UPGRADE_INSECURE_REQUESTS)
154+
modified_csp_config = config.csp.dup
155+
modified_csp_config.update_directive(ContentSecurityPolicy::UPGRADE_INSECURE_REQUESTS, false)
156+
header_name, value = ContentSecurityPolicy.make_header(modified_csp_config)
157+
headers[header_name] = value if header_name && value
158+
end
159+
160+
if !config.csp_report_only.opt_out? && config.csp_report_only.directive_value(ContentSecurityPolicy::UPGRADE_INSECURE_REQUESTS)
161+
modified_csp_report_only_config = config.csp_report_only.dup
162+
modified_csp_report_only_config.update_directive(ContentSecurityPolicy::UPGRADE_INSECURE_REQUESTS, false)
163+
header_name, value = ContentSecurityPolicy.make_header(modified_csp_report_only_config)
164+
headers[header_name] = value if header_name && value
165+
end
149166
end
150167
headers
151168
end

spec/lib/secure_headers_spec.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,68 @@ module SecureHeaders
436436

437437
end
438438
end
439+
440+
it "does not set upgrade-insecure-requests if request is over HTTP" do
441+
reset_config
442+
Configuration.default do |config|
443+
config.csp = {
444+
default_src: %w('self'),
445+
script_src: %w('self'),
446+
upgrade_insecure_requests: true
447+
}
448+
end
449+
450+
plaintext_request = Rack::Request.new({})
451+
hash = SecureHeaders.header_hash_for(plaintext_request)
452+
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src 'self'")
453+
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).not_to include("upgrade-insecure-requests")
454+
end
455+
456+
it "sets upgrade-insecure-requests if request is over HTTPS" do
457+
reset_config
458+
Configuration.default do |config|
459+
config.csp = {
460+
default_src: %w('self'),
461+
script_src: %w('self'),
462+
upgrade_insecure_requests: true
463+
}
464+
end
465+
466+
https_request = Rack::Request.new("HTTPS" => "on")
467+
hash = SecureHeaders.header_hash_for(https_request)
468+
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src 'self'; upgrade-insecure-requests")
469+
end
470+
471+
it "does not set upgrade-insecure-requests in report-only mode if request is over HTTP" do
472+
reset_config
473+
Configuration.default do |config|
474+
config.csp_report_only = {
475+
default_src: %w('self'),
476+
script_src: %w('self'),
477+
upgrade_insecure_requests: true
478+
}
479+
end
480+
481+
plaintext_request = Rack::Request.new({})
482+
hash = SecureHeaders.header_hash_for(plaintext_request)
483+
expect(hash[ContentSecurityPolicyReportOnlyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src 'self'")
484+
expect(hash[ContentSecurityPolicyReportOnlyConfig::HEADER_NAME]).not_to include("upgrade-insecure-requests")
485+
end
486+
487+
it "sets upgrade-insecure-requests in report-only mode if request is over HTTPS" do
488+
reset_config
489+
Configuration.default do |config|
490+
config.csp_report_only = {
491+
default_src: %w('self'),
492+
script_src: %w('self'),
493+
upgrade_insecure_requests: true
494+
}
495+
end
496+
497+
https_request = Rack::Request.new("HTTPS" => "on")
498+
hash = SecureHeaders.header_hash_for(https_request)
499+
expect(hash[ContentSecurityPolicyReportOnlyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src 'self'; upgrade-insecure-requests")
500+
end
439501
end
440502
end
441503

0 commit comments

Comments
 (0)