From a51b36fb75044949c9c028ba9f788d617f6c5dae Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 4 Nov 2022 16:10:24 +0100 Subject: [PATCH] Fix building CSP policy You can't use 'none' as a CSP Policy if there's other things among Signed-off-by: Thomas Citharel --- config/config.exs | 2 +- lib/web/plugs/http_security_plug.ex | 32 +++++++++++++++------- test/web/plugs/http_security_plug_test.exs | 2 +- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/config/config.exs b/config/config.exs index fef8c6ddd..dd5e28b6a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -368,7 +368,7 @@ config :mobilizon, Mobilizon.Service.GlobalSearch, config :mobilizon, Mobilizon.Service.GlobalSearch.SearchMobilizon, endpoint: "https://search.joinmobilizon.org", csp_policy: [ - img_src: "search.joinmobilizon.org" + img_src: ["search.joinmobilizon.org"] ] # Import environment specific config. This must remain at the bottom diff --git a/lib/web/plugs/http_security_plug.ex b/lib/web/plugs/http_security_plug.ex index 912c98657..862803b49 100644 --- a/lib/web/plugs/http_security_plug.ex +++ b/lib/web/plugs/http_security_plug.ex @@ -119,13 +119,8 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do font_src = [@font_src] ++ [get_csp_config(:font_src, options)] - frame_src = if Config.get(:env) == :dev, do: "frame-src 'self' ", else: "frame-src 'none' " - frame_src = [frame_src] ++ [get_csp_config(:frame_src, options)] - - frame_ancestors = - if Config.get(:env) == :dev, do: "frame-ancestors 'self' ", else: "frame-ancestors 'none' " - - frame_ancestors = [frame_ancestors] ++ [get_csp_config(:frame_ancestors, options)] + frame_src = build_csp_field(:frame_src, options) + frame_ancestors = build_csp_field(:frame_ancestors, options) report = if report_uri, do: ["report-uri ", report_uri, " ; report-to csp-endpoint"] insecure = if scheme == "https", do: "upgrade-insecure-requests" @@ -162,9 +157,9 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do @spec get_csp_config(atom(), Keyword.t()) :: iodata() defp get_csp_config(type, options) do config_policy = Keyword.get(options, type, Config.get([:http_security, :csp_policy, type])) - front_end_analytics_policy = [Keyword.get(FrontEndAnalytics.csp(), type, [])] - global_search_policy = [Keyword.get(GlobalSearch.service().csp(), type, [])] - pictures_policy = [Keyword.get(Pictures.service().csp(), type, [])] + front_end_analytics_policy = Keyword.get(FrontEndAnalytics.csp(), type, []) + global_search_policy = Keyword.get(GlobalSearch.service().csp(), type, []) + pictures_policy = Keyword.get(Pictures.service().csp(), type, []) resource_providers = Config.get([Mobilizon.Service.ResourceProviders, :csp_policy, type], []) @@ -175,4 +170,21 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do " " ) end + + defp build_csp_field(type, options) do + csp_config = get_csp_config(type, options) + + csp_config = + if Config.get(:env) == :dev do + [csp_config] ++ ["'self'"] + else + if csp_config == "" do + ["'none'"] + else + [csp_config] + end + end + + Enum.join([type |> to_string() |> String.replace("_", "-")] ++ csp_config, " ") + end end diff --git a/test/web/plugs/http_security_plug_test.exs b/test/web/plugs/http_security_plug_test.exs index e36921fec..7b8a2ef7f 100644 --- a/test/web/plugs/http_security_plug_test.exs +++ b/test/web/plugs/http_security_plug_test.exs @@ -93,7 +93,7 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlugTest do [csp] = Conn.get_resp_header(conn, "content-security-policy") assert csp =~ - ~r/script-src 'self' 'unsafe-eval' 'sha256-[\w+\/=]*' 'sha256-[\w+\/=]*' example.com matomo.example.com\s+;/ + ~r/script-src 'self' 'unsafe-eval' 'sha256-[\w+\/=]*' 'sha256-[\w+\/=]*' example.com matomo.example.com;/ end end