Liam White
Using a Content-Security-Policy in Phoenix applications

In Philomena, we are using this Plug module in our browser pipeline to keep things clean for clients:

defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
  alias Plug.Conn

  def init([]) do
    cdn_uri = cdn_uri()
    camo_uri = camo_uri()

    csp_value =
      "default-src 'self' #{cdn_uri}; object-src 'none'; " <>
        "frame-ancestors 'none'; frame-src 'none'; form-action 'self'; " <>
        "manifest-src 'self'; img-src 'self' data: #{cdn_uri} #{camo_uri}; " <>
        "block-all-mixed-content"

    [csp_value: csp_value]
  end

  def call(conn, csp_value: csp_value) do
    Conn.put_resp_header(conn, "content-security-policy", csp_value)
  end

  defp cdn_uri, do: Application.get_env(:philomena, :cdn_host) |> to_uri()
  defp camo_uri, do: Application.get_env(:philomena, :camo_host) |> to_uri()

  defp to_uri(host) when host in [nil, ""], do: ""
  defp to_uri(host), do: URI.to_string(%URI{scheme: "https", host: host})
end

Note that this blocks things like inline styles, which many websites depend on. You may want to explicitly set style-src to allow 'unsafe-inline' if you need this functionality, but beware that an attacker HTML injection could be combined with inline styles to exfiltrate user data.