Module: GovukContentSecurityPolicy

Defined in:
lib/govuk_app_config/govuk_content_security_policy.rb

Constant Summary collapse

GOVUK_DOMAINS =

Generate a Content Security Policy (CSP) directive.

Before making any changes please read our documentation: docs.publishing.service.gov.uk/manual/content-security-policy.html

If you are making a change here you should consider 2 basic rules of thumb:

  1. Are you creating a XSS risk? Adding unsafe-* declarations, allowing data: URLs or being overly permissive (e.g. https) risks these

  2. Is this change needed globally, if it’s just one or two apps the change should be applied in them directly.

[
  "*.publishing.service.gov.uk",
  "*.#{ENV['GOVUK_APP_DOMAIN_EXTERNAL'] || ENV['GOVUK_APP_DOMAIN'] || 'dev.gov.uk'}",
  "www.gov.uk",
  "*.dev.gov.uk",
].uniq.freeze
GOOGLE_ANALYTICS_DOMAINS =
%w[www.google-analytics.com
ssl.google-analytics.com
stats.g.doubleclick.net
www.googletagmanager.com
www.region1.google-analytics.com
region1.google-analytics.com].freeze
GOOGLE_STATIC_DOMAINS =
%w[www.gstatic.com].freeze

Class Method Summary collapse

Class Method Details

.build_policy(policy) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/govuk_app_config/govuk_content_security_policy.rb', line 27

def self.build_policy(policy)
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src
  policy.default_src :self

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri
  policy.base_uri :none

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src
  # Note: we purposely don't include `data:` here because it produces a security risk.
  policy.img_src :self,
                 *GOVUK_DOMAINS,
                 *GOOGLE_ANALYTICS_DOMAINS, # Tracking pixels
                 # Speedcurve real user monitoring (RUM) - as per: https://support.speedcurve.com/docs/add-rum-to-your-csp
                 "lux.speedcurve.com",
                 # Some content still links to an old domain we used to use
                 "assets.digital.cabinet-office.gov.uk",
                 # Allow YouTube thumbnails
                 "https://img.youtube.com",
                 "https://i.ytimg.com"

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
  # Note: we purposely don't include `data:`, `unsafe-inline` or `unsafe-eval` because
  # they are security risks, if you need them for a legacy app please only apply them at
  # an app level.
  policy.script_src :self,
                    *GOOGLE_ANALYTICS_DOMAINS,
                    *GOOGLE_STATIC_DOMAINS,
                    # Allow YouTube Embeds (Govspeak turns YouTube links into embeds)
                    "*.ytimg.com",
                    "www.youtube.com",
                    "www.youtube-nocookie.com"

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
  # Note: we purposely don't include `data:`, `unsafe-inline` or `unsafe-eval` because
  # they are security risks, if you need them for a legacy app please only apply them at
  # an app level.
  policy.style_src :self, *GOOGLE_STATIC_DOMAINS

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src
  # Note: we purposely don't include data here because it produces a security risk.
  policy.font_src :self

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src
  policy.connect_src :self,
                     *GOVUK_DOMAINS,
                     *GOOGLE_ANALYTICS_DOMAINS,
                     # Speedcurve real user monitoring (RUM) - as per: https://support.speedcurve.com/docs/add-rum-to-your-csp
                     "lux.speedcurve.com",
                     "gds-single-consent-staging.app",
                     "gds-single-consent.app"

  # Disallow all <object>, <embed>, and <applet> elements
  #
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src
  policy.object_src :none

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
  policy.frame_src :self, *GOVUK_DOMAINS, "www.youtube.com", "www.youtube-nocookie.com" # Allow youtube embeds

  # Disallow non-gov.uk domains from embeding a page using <frame>, <iframe>, <object>, or <embed> to prevent clickjacking
  #
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
  policy.frame_ancestors :self, *GOVUK_DOMAINS

  policy.report_uri ENV["GOVUK_CSP_REPORT_URI"] if ENV.include?("GOVUK_CSP_REPORT_URI")
end

.configure {|policy| ... } ⇒ Object

Yields:

  • (policy)


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/govuk_app_config/govuk_content_security_policy.rb', line 94

def self.configure
  Rails.application.config.content_security_policy_report_only = ENV.include?("GOVUK_CSP_REPORT_ONLY")

  # Sets a nonce per request that can be set on script-src and style-src
  # directives depending on the value of Rails.application.config.content_security_policy_nonce_directives
  #
  # Note: if an application needs to set unsafe-inline they will need to
  # unset this generator (by setting this config option to nil in their application)
  Rails.application.config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) }

  # This only applies the nonce generator to the script-src directive. We need this to
  # use unsafe-inline for style-src as a nonce will override it.
  #
  # When we want to apply it to style-src we can remove this line as the Rails default
  # is for both script-src and style-src
  Rails.application.config.content_security_policy_nonce_directives = %w[script-src]

  policy = Rails.application.config.content_security_policy(&method(:build_policy))

  # # allow apps to customise the CSP by passing a block e.g:
  # GovukContentSecuirtyPolicy.configure do |policy|
  #   policy.image_src(*policy.image_src, "https://i.ytimg.com")
  # end
  yield(policy) if block_given?

  policy
end