From 717ec0e043148e9bb62e7f185bbaedb6fd5ffdd5 Mon Sep 17 00:00:00 2001 From: Ryan Kotval Date: Thu, 27 Jun 2024 14:55:06 -0500 Subject: [PATCH] feat(ContentSecurityPolicy): Add a content security policy (#2094) (#2102) * feat(ContentSecurityPolicy): Add a content security policy (#2094) This reverts commit 29a90a8b1a229b016493d44c13a99f730a3af2bc. * Updated the CPS * Added more csp hosts * Added more domains * Added more urls, and fixed google analytics typo * Added doubleclick to the connect csp * Added more linkedin images --- config/runtime.exs | 49 ++++++++++++++++++++++++++++++++++++++++ lib/dotcom_web/router.ex | 11 ++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/config/runtime.exs b/config/runtime.exs index e7298b6779..d2c2fe4679 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -213,3 +213,52 @@ if System.get_env("LOGGER_LEVEL") in ~w(emergency alert critical error warning n config :logger, level: String.to_atom(System.get_env("LOGGER_LEVEL")) config :logger, :console, level: String.to_atom(System.get_env("LOGGER_LEVEL")) end + +# Extract the host fron the sentry dsn +sentry_dsn_host = + case Regex.run(~r/@(.*)\//, System.get_env("SENTRY_DSN", ""), capture: :all_but_first) do + nil -> "" + [match | _] -> match + end + +# Set the content security policy +case config_env() do + :prod -> + config :dotcom, + :content_security_policy_definition, + Enum.join( + [ + "default-src 'none'", + "img-src 'self' cdn.mbta.com #{System.get_env("STATIC_HOST", "")} #{System.get_env("CMS_API_BASE_URL", "")} px.ads.linkedin.com www.linkedin.com www.facebook.com *.google.com *.googleapis.com *.gstatic.com *.s3.amazonaws.com data: i.ytimg.com www.googletagmanager.com", + "style-src 'self' 'unsafe-inline' www.gstatic.com #{System.get_env("STATIC_HOST", "")} cdn.jsdelivr.net", + "script-src 'self' 'unsafe-eval' 'unsafe-inline' #{System.get_env("STATIC_HOST", "")} insitez.blob.core.windows.net snap.licdn.com connect.facebook.net www.instagram.com www.google-analytics.com *.google.com www.gstatic.com www.googletagmanager.com *.googleapis.com data.mbta.com", + "font-src 'self' #{System.get_env("STATIC_HOST", "")}", + "connect-src 'self' *.googleapis.com #{sentry_dsn_host || ""} www.google-analytics.com www.google.com px.ads.linkedin.com stats.g.doubleclick.net", + "frame-src 'self' data.mbta.com www.youtube.com www.google.com cdn.knightlab.com livestream.com www.instagram.com" + ], + "; " + ) + + :dev -> + config :dotcom, + :content_security_policy_definition, + Enum.join( + [ + "default-src 'none'", + "img-src 'self' cdn.mbta.com #{System.get_env("CMS_API_BASE_URL", "")} *.google.com *.googleapis.com *.gstatic.com mbta-map-tiles-dev.s3.amazonaws.com data: i.ytimg.com www.googletagmanager.com", + "style-src 'self' 'unsafe-inline' localhost:* www.gstatic.com", + "script-src 'self' 'unsafe-eval' 'unsafe-inline' localhost:* www.instagram.com *.google.com www.gstatic.com www.googletagmanager.com www.google-analytics.com *.googleapis.com data.mbta.com", + "font-src 'self' localhost:*", + "connect-src 'self' localhost:* ws://localhost:* *.googleapis.com", + "frame-src 'self' localhost:* data.mbta.com www.youtube.com www.google.com cdn.knightlab.com livestream.com www.instagram.com" + ], + "; " + ) + + :test -> + config :dotcom, :content_security_policy_definition, "" + + # Unknown env, reject all + _ -> + config :dotcom, :content_security_policy_definition, "default-src 'none'" +end diff --git a/lib/dotcom_web/router.ex b/lib/dotcom_web/router.ex index 818e2a58f1..29685e5e1a 100644 --- a/lib/dotcom_web/router.ex +++ b/lib/dotcom_web/router.ex @@ -18,7 +18,7 @@ defmodule DotcomWeb.Router do plug(:fetch_session) plug(:fetch_flash) plug(:fetch_cookies) - plug(:put_secure_browser_headers) + plug(:put_secure_browser_headers_runtime, %{}) plug(:put_root_layout, {DotcomWeb.LayoutView, :root}) plug(DotcomWeb.Plugs.CanonicalHostname) plug(DotcomWeb.Plugs.Banner) @@ -312,4 +312,13 @@ defmodule DotcomWeb.Router do Plug.Conn.put_resp_header(conn, "x-robots-tag", "noindex") end end + + defp put_secure_browser_headers_runtime(conn, default_headers) do + runtime_headers = %{ + "content-security-policy" => + Application.get_env(:dotcom, :content_security_policy_definition) + } + + put_secure_browser_headers(conn, Map.merge(default_headers, runtime_headers)) + end end