summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock4
-rw-r--r--config/initializers/secure_headers.rb109
3 files changed, 116 insertions, 0 deletions
diff --git a/Gemfile b/Gemfile
index 6ae9086a541..8a30a819660 100644
--- a/Gemfile
+++ b/Gemfile
@@ -349,3 +349,6 @@ gem 'health_check', '~> 2.1.0'
# System information
gem 'vmstat', '~> 2.1.0'
gem 'sys-filesystem', '~> 1.1.6'
+
+# Secure headers for Content Security Policy
+gem 'secure_headers', '~> 3.3'
diff --git a/Gemfile.lock b/Gemfile.lock
index 9ec5fe12820..f3f4d895ae4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -645,6 +645,8 @@ GEM
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
+ secure_headers (3.3.2)
+ useragent
seed-fu (2.3.6)
activerecord (>= 3.1)
activesupport (>= 3.1)
@@ -767,6 +769,7 @@ GEM
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uniform_notifier (1.9.0)
+ useragent (0.16.7)
uuid (2.3.8)
macaddr (~> 1.0)
version_sorter (2.0.0)
@@ -944,6 +947,7 @@ DEPENDENCIES
sass-rails (~> 5.0.0)
scss_lint (~> 0.47.0)
sdoc (~> 0.3.20)
+ secure_headers (~> 3.3)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven (~> 1.1.0)
diff --git a/config/initializers/secure_headers.rb b/config/initializers/secure_headers.rb
new file mode 100644
index 00000000000..9fd24a667cc
--- /dev/null
+++ b/config/initializers/secure_headers.rb
@@ -0,0 +1,109 @@
+# CSP headers have to have single quotes, so failures relating to quotes
+# inside Ruby string arrays are irrelevant.
+# rubocop:disable Lint/PercentStringArray
+require 'gitlab/current_settings'
+include Gitlab::CurrentSettings
+
+# If Sentry is enabled and the Rails app is running in production mode,
+# this will construct the Report URI for Sentry.
+if Rails.env.production? && current_application_settings.sentry_enabled
+ uri = URI.parse(current_application_settings.sentry_dsn)
+ CSP_REPORT_URI = "#{uri.scheme}://#{uri.host}/api#{uri.path}/csp-report/?sentry_key=#{uri.user}"
+else
+ CSP_REPORT_URI = ''
+end
+
+# Content Security Policy Headers
+# For more information on CSP see:
+# - https://gitlab.com/gitlab-org/gitlab-ce/issues/18231
+# - https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives
+SecureHeaders::Configuration.default do |config|
+ # Mark all cookies as "Secure", "HttpOnly", and "SameSite=Strict".
+ config.cookies = {
+ secure: true,
+ httponly: true,
+ samesite: {
+ strict: true
+ }
+ }
+ config.x_content_type_options = "nosniff"
+ config.x_xss_protection = "1; mode=block"
+ config.x_download_options = "noopen"
+ config.x_permitted_cross_domain_policies = "none"
+ config.referrer_policy = "origin-when-cross-origin"
+ config.csp = {
+ # "Meta" values.
+ report_only: true,
+ preserve_schemes: true,
+
+ # "Directive" values.
+ # Default source allows nothing, more permissive values are set per-policy.
+ default_src: %w('none'),
+ # (Deprecated) Don't allow iframes.
+ frame_src: %w('none'),
+ # Only allow XMLHTTPRequests from the GitLab instance itself.
+ connect_src: %w('self'),
+ # Only load local fonts.
+ font_src: %w('self'),
+ # Load local images, any external image available over HTTPS.
+ img_src: %w(* 'self' data:),
+ # Audio and video can't be played on GitLab currently, so it's disabled.
+ media_src: %w('none'),
+ # Don't allow <object>, <embed>, or <applet> elements.
+ object_src: %w('none'),
+ # Allow local scripts and inline scripts.
+ script_src: %w('unsafe-inline' 'unsafe-eval' 'self'),
+ # Allow local stylesheets and inline styles.
+ style_src: %w('unsafe-inline' 'self'),
+ # The URIs that a user agent may use as the document base URL.
+ base_uri: %w('self'),
+ # Only allow local iframes and service workers
+ child_src: %w('self'),
+ # Only submit form information to the GitLab instance.
+ form_action: %w('self'),
+ # Disallow any parents from embedding a page in an iframe.
+ frame_ancestors: %w('none'),
+ # Don't allow any plugins (Flash, Shockwave, etc.)
+ plugin_types: %w(),
+ # Blocks all mixed (HTTP) content.
+ block_all_mixed_content: true,
+ # Upgrades insecure requests to HTTPS when possible.
+ upgrade_insecure_requests: true
+ }
+
+ # Reports are sent to Sentry if it's enabled.
+ if current_application_settings.sentry_enabled
+ config.csp[:report_uri] = %W(#{CSP_REPORT_URI})
+ end
+
+ # Allow Bootstrap Linter in development mode.
+ if Rails.env.development?
+ config.csp[:script_src] << "maxcdn.bootstrapcdn.com"
+ end
+
+ # reCAPTCHA
+ if current_application_settings.recaptcha_enabled
+ config.csp[:script_src] << "https://www.google.com/recaptcha/"
+ config.csp[:script_src] << "https://www.gstatic.com/recaptcha/"
+ config.csp[:frame_src] << "https://www.google.com/recaptcha/"
+ config.x_frame_options = "SAMEORIGIN"
+ end
+
+ # Gravatar
+ if current_application_settings.gravatar_enabled?
+ config.csp[:img_src] << "www.gravatar.com"
+ config.csp[:img_src] << "secure.gravatar.com"
+ config.csp[:img_src] << Gitlab.config.gravatar.host
+ end
+
+ # Piwik
+ if Gitlab.config.extra.has_key?('piwik_url') && Gitlab.config.extra.has_key?('piwik_site_id')
+ config.csp[:script_src] << Gitlab.config.extra.piwik_url
+ config.csp[:img_src] << Gitlab.config.extra.piwik_url
+ end
+
+ # Google Analytics
+ if Gitlab.config.extra.has_key?('google_analytics_id')
+ config.csp[:script_src] << "https://www.google-analytics.com"
+ end
+end