Module: PublishingPlatformContentSecurityPolicy

Defined in:
lib/publishing_platform_app_config/publishing_platform_content_security_policy.rb

Constant Summary collapse

PUBLISHING_PLATFORM_DOMAINS =

Generate a Content Security Policy (CSP) directive.

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-platform.co.uk",
  "*.dev.publishing-platform.co.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



23
24
25
26
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
# File 'lib/publishing_platform_app_config/publishing_platform_content_security_policy.rb', line 23

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,
                 *PUBLISHING_PLATFORM_DOMAINS,
                 *GOOGLE_ANALYTICS_DOMAINS, # Tracking pixels
                 # 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
                    "*.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,
                     *PUBLISHING_PLATFORM_DOMAINS,
                     *GOOGLE_ANALYTICS_DOMAINS

  # 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, *PUBLISHING_PLATFORM_DOMAINS, "www.youtube.com", "www.youtube-nocookie.com" # Allow youtube embeds

  # Disallow non-publishing-platform.co.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, *PUBLISHING_PLATFORM_DOMAINS

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

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

Yields:

  • (policy)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/publishing_platform_app_config/publishing_platform_content_security_policy.rb', line 82

def self.configure
  Rails.application.config.content_security_policy_report_only = ENV.include?("PUBLISHING_PLATFORM_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:
  # PublishingPlatformContentSecurityPolicy.configure do |policy|
  #   policy.image_src(*policy.image_src, "https://i.ytimg.com")
  # end
  yield(policy) if block_given?

  policy
end