Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions app/controllers/concerns/idv/document_capture_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,6 @@ module DocumentCaptureConcern
def override_document_capture_step_csp
return if params[:step] != 'document_capture'

if FeatureManagement.rails_csp_tooling_enabled?
override_document_capture_step_csp_with_rails_csp_tooling
else
override_document_capture_step_csp_with_secure_headers
end
end

def override_document_capture_step_csp_with_secure_headers
SecureHeaders.append_content_security_policy_directives(
request,
# required to run wasm until wasm-eval is available
script_src: ['\'unsafe-eval\''],
# required because acuant styles its own elements with inline style attributes
style_src: ['\'unsafe-inline\''],
# required for retrieving image dimensions from uploaded images
img_src: ['blob:'],
)
end

def override_document_capture_step_csp_with_rails_csp_tooling
policy = current_content_security_policy
policy.script_src(*policy.script_src, :unsafe_eval)
policy.style_src(*policy.style_src, :unsafe_inline)
Expand Down
12 changes: 0 additions & 12 deletions app/controllers/concerns/secure_headers_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ def apply_secure_headers_override
end

def override_form_action_csp(uris)
if FeatureManagement.rails_csp_tooling_enabled?
apply_secure_headers_override_with_rails_csp_tooling(uris)
else
apply_secure_headers_override_with_secure_headers(uris)
end
end

def apply_secure_headers_override_with_secure_headers(uris)
override_content_security_policy_directives(form_action: uris)
end

def apply_secure_headers_override_with_rails_csp_tooling(uris)
policy = current_content_security_policy
policy.form_action(*uris)
request.content_security_policy = policy
Expand Down
12 changes: 2 additions & 10 deletions app/helpers/secure_headers_helper.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
module SecureHeadersHelper
def backwards_compatible_javascript_tag(*args, **opts, &block)
if FeatureManagement.rails_csp_tooling_enabled?
javascript_tag(*args, opts.merge(nonce: true), &block)
else
nonced_javascript_tag(*args, **opts, &block)
end
javascript_tag(*args, opts.merge(nonce: true), &block)
end

def add_document_capture_image_urls_to_csp(request, urls)
cleaned_urls = urls.compact.map do |url|
URI(url).tap { |uri| uri.query = nil }.to_s
end

if FeatureManagement.rails_csp_tooling_enabled?
add_document_capture_image_urls_to_csp_with_rails_csp_tooling(request, cleaned_urls)
else
add_document_capture_image_urls_to_csp_with_secure_headers(request, cleaned_urls)
end
add_document_capture_image_urls_to_csp_with_rails_csp_tooling(request, cleaned_urls)
end

def add_document_capture_image_urls_to_csp_with_secure_headers(request, urls)
Expand Down
1 change: 0 additions & 1 deletion config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ push_notifications_enabled: false
pwned_passwords_file_path: 'pwned_passwords/pwned_passwords.txt'
rack_mini_profiler: false
rack_timeout_service_timeout_seconds: 15
rails_csp_tooling_enabled: true
rails_mailer_previews_enabled: false
reauthn_window: 120
recovery_code_length: 4
Expand Down
108 changes: 53 additions & 55 deletions config/initializers/content_security_policy.rb
Original file line number Diff line number Diff line change
@@ -1,67 +1,65 @@
require 'feature_management'

if FeatureManagement.rails_csp_tooling_enabled?
# rubocop:disable Metrics/BlockLength
Rails.application.config.content_security_policy do |policy|
connect_src = ["'self'", '*.nr-data.net', '*.google-analytics.com', 'us.acas.acuant.net']
# rubocop:disable Metrics/BlockLength
Rails.application.config.content_security_policy do |policy|
connect_src = ["'self'", '*.nr-data.net', '*.google-analytics.com', 'us.acas.acuant.net']

font_src = [:self, :data, IdentityConfig.store.asset_host.presence].compact
font_src = [:self, :data, IdentityConfig.store.asset_host.presence].compact

image_src = [
"'self'",
'data:',
'login.gov',
IdentityConfig.store.asset_host.presence,
'idscangoweb.acuant.com',
IdentityConfig.store.aws_region.presence &&
"https://s3.#{IdentityConfig.store.aws_region}.amazonaws.com",
].select(&:present?)
image_src = [
"'self'",
'data:',
'login.gov',
IdentityConfig.store.asset_host.presence,
'idscangoweb.acuant.com',
IdentityConfig.store.aws_region.presence &&
"https://s3.#{IdentityConfig.store.aws_region}.amazonaws.com",
].select(&:present?)

script_src = [
:self,
'js-agent.newrelic.com',
'*.nr-data.net',
'dap.digitalgov.gov',
'*.google-analytics.com',
IdentityConfig.store.asset_host.presence,
].compact
script_src = [
:self,
'js-agent.newrelic.com',
'*.nr-data.net',
'dap.digitalgov.gov',
'*.google-analytics.com',
IdentityConfig.store.asset_host.presence,
].compact

script_src = [:self, :unsafe_eval] if !Rails.env.production?
script_src = [:self, :unsafe_eval] if !Rails.env.production?

style_src = [:self, IdentityConfig.store.asset_host.presence].compact
style_src = [:self, IdentityConfig.store.asset_host.presence].compact

if ENV['WEBPACK_PORT']
connect_src << "ws://localhost:#{ENV['WEBPACK_PORT']}"
script_src << "localhost:#{ENV['WEBPACK_PORT']}"
end

if !IdentityConfig.store.disable_csp_unsafe_inline
script_src << :unsafe_inline
style_src << :unsafe_inline
end

if IdentityConfig.store.rails_mailer_previews_enabled
style_src << :unsafe_inline
# CSP 2.0 only; overriden by x_frame_options in some browsers
policy.frame_ancestors :self
end
if ENV['WEBPACK_PORT']
connect_src << "ws://localhost:#{ENV['WEBPACK_PORT']}"
script_src << "localhost:#{ENV['WEBPACK_PORT']}"
end

policy.default_src :self
policy.child_src :self # CSP 2.0 only; replaces frame_src
policy.form_action :self
policy.block_all_mixed_content true # CSP 2.0 only;
policy.connect_src(*connect_src.flatten.compact)
policy.font_src(*font_src)
policy.img_src(*image_src)
policy.media_src :self
policy.object_src :none
policy.script_src(*script_src)
policy.style_src(*style_src)
policy.base_uri :self
if !IdentityConfig.store.disable_csp_unsafe_inline
script_src << :unsafe_inline
style_src << :unsafe_inline
end
# rubocop:enable Metrics/BlockLength
Rails.application.configure do
config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
config.content_security_policy_nonce_directives = ['script-src']

if IdentityConfig.store.rails_mailer_previews_enabled
style_src << :unsafe_inline
# CSP 2.0 only; overriden by x_frame_options in some browsers
policy.frame_ancestors :self
end

policy.default_src :self
policy.child_src :self # CSP 2.0 only; replaces frame_src
policy.form_action :self
policy.block_all_mixed_content true # CSP 2.0 only;
policy.connect_src(*connect_src.flatten.compact)
policy.font_src(*font_src)
policy.img_src(*image_src)
policy.media_src :self
policy.object_src :none
policy.script_src(*script_src)
policy.style_src(*style_src)
policy.base_uri :self
end
# rubocop:enable Metrics/BlockLength
Rails.application.configure do
config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
config.content_security_policy_nonce_directives = ['script-src']
end
43 changes: 19 additions & 24 deletions config/initializers/secure_headers.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
require 'feature_management'

if FeatureManagement.rails_csp_tooling_enabled?
Rails.application.configure do
config.ssl_options = {
secure_cookies: true,
hsts: { preload: true, expires: 1.year, subdomains: true },
}
Rails.application.configure do
config.ssl_options = {
secure_cookies: true,
hsts: { preload: true, expires: 1.year, subdomains: true },
}

config.action_dispatch.default_headers.merge!(
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block',
'X-Download-Options' => 'noopen',
)
end
config.action_dispatch.default_headers.merge!(
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block',
'X-Download-Options' => 'noopen',
)
end

SecureHeaders::Configuration.default do |config| # rubocop:disable Metrics/BlockLength
Expand Down Expand Up @@ -69,18 +67,15 @@
default_csp_config[:script_src] << "localhost:#{ENV['WEBPACK_PORT']}"
end

if FeatureManagement.rails_csp_tooling_enabled?
config.csp = SecureHeaders::OPT_OUT
else
config.csp = default_csp_config
config.cookies = {
secure: true, # mark all cookies as "Secure"
httponly: true, # mark all cookies as "HttpOnly"
samesite: {
lax: true, # SameSitesetting.
},
}
end
config.csp = SecureHeaders::OPT_OUT

config.cookies = {
secure: true, # mark all cookies as "Secure"
httponly: true, # mark all cookies as "HttpOnly"
samesite: {
lax: true, # SameSite setting.
},
}

# Temporarily disabled until we configure pinning. See GitHub issue #1895.
# config.hpkp = {
Expand Down
4 changes: 0 additions & 4 deletions lib/feature_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,4 @@ def self.voip_allowed_phones
allowed_phones.map { |p| Phonelib.parse(p).e164 }.to_set
end
end

def self.rails_csp_tooling_enabled?
IdentityConfig.store.rails_csp_tooling_enabled == true
end
end
1 change: 0 additions & 1 deletion lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ def self.build_store(config_map)
config.add(:pwned_passwords_file_path, type: :string)
config.add(:rack_mini_profiler, type: :boolean)
config.add(:rack_timeout_service_timeout_seconds, type: :integer)
config.add(:rails_csp_tooling_enabled, type: :boolean)
config.add(:rails_mailer_previews_enabled, type: :boolean)
config.add(:reauthn_window, type: :integer)
config.add(:recovery_code_length, type: :integer)
Expand Down