Make your own CSP headers.
For example:
plug :put_secure_browser_headers, %{"content-security-policy" => MyAppWeb.CSP.header_value()}
with csp module like this:
defmodule MyAppWeb.CSP do
@moduledoc """
Content-Security-Policy
https://www.w3.org/TR/CSP2/#directives
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
"""
@hcaptcha ["https://hcaptcha.com", "https://*.hcaptcha.com"]
@stripe ["https://js.stripe.com"]
@google_fonts ["https://fonts.googleapis.com"]
@env_specific_csp if Mix.env() == :dev,
do: ["'unsafe-inline'", "'unsafe-eval'", "blob:", "http://localhost:4007"],
else: []
@header_kvp_list [
default_src: ["'self'"],
img_src: ["'self'", "data:"] ++ @env_specific_csp,
script_src: ["'self'"] ++ @hcaptcha ++ @stripe ++ @env_specific_csp,
object_src: ["'self'"],
frame_src: ["'self'"] ++ @hcaptcha ++ @stripe,
style_src: ["'self'", "'unsafe-inline'"] ++ @hcaptcha ++ @stripe ++ @google_fonts ++ @env_specific_csp,
connect_src: ["'self'"] ++ @hcaptcha ++ @stripe
]
@spec header_value() :: String.t()
def header_value do
configured_header_kvp_list = Application.get_env(:my_app, :csp_headers, [])
@header_kvp_list
|> Keyword.merge(configured_header_kvp_list)
|> Enum.map_join("; ", &map_header_kvp_to_string/1)
end
defp map_header_kvp_to_string({atom_key, list_value}) do
string_key = atom_key |> to_string() |> String.replace("_", "-")
string_value = Enum.join(list_value, " ")
"#{string_key} #{string_value}"
end
end
That is lifted straight from one of my hobby projects. localhost:4007 is an imgproxy server.
Anyway, I think the thing that is needed is the google fonts bit? Not sure, but this solved heroicons for me in terms of CSP.
Edit 26 March 2024: read this instead: Blog Post: Content Security Policy header with Phoenix LiveView