From d6459688efc05ed786bb8dbd07099f4e6d084b1f Mon Sep 17 00:00:00 2001 From: Pieter Michels Date: Thu, 15 Dec 2022 21:10:36 +0100 Subject: [PATCH] chore: add level 3 CSP directives --- config/config.exs | 2 +- lib/content_security_policy/directive.ex | 18 ++++++++- lib/content_security_policy/policy.ex | 12 +++++- mix.exs | 2 +- mix.lock | 37 ++++++++++--------- .../plug/add_nonce_test.exs | 2 +- 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/config/config.exs b/config/config.exs index 17675a4..eea475e 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this diff --git a/lib/content_security_policy/directive.ex b/lib/content_security_policy/directive.ex index 728774a..548953d 100644 --- a/lib/content_security_policy/directive.ex +++ b/lib/content_security_policy/directive.ex @@ -12,7 +12,8 @@ defmodule ContentSecurityPolicy.Directive do alias ContentSecurityPolicy.Policy @opaque valid_directive :: - :child_src + :base_uri + | :child_src | :connect_src | :default_src | :font_src @@ -20,13 +21,20 @@ defmodule ContentSecurityPolicy.Directive do | :frame_ancestors | :frame_src | :img_src + | :manifest_src | :media_src | :object_src | :plugin_types + | :prefetch_src | :report_uri | :sandbox | :script_src + | :script_src_attr + | :script_src_elem | :style_src + | :style_src_elem + | :webrtc + | :worker_src @valid_directives Policy.__struct__() |> Map.keys() @@ -39,6 +47,7 @@ defmodule ContentSecurityPolicy.Directive do Raises an `ArgumentError` if the directive is not valid. """ @spec validate_directive!(valid_directive()) :: :ok + def validate_directive!(:base_uri), do: :ok def validate_directive!(:child_src), do: :ok def validate_directive!(:connect_src), do: :ok def validate_directive!(:default_src), do: :ok @@ -47,13 +56,20 @@ defmodule ContentSecurityPolicy.Directive do def validate_directive!(:frame_ancestors), do: :ok def validate_directive!(:frame_src), do: :ok def validate_directive!(:img_src), do: :ok + def validate_directive!(:manifest_src), do: :ok def validate_directive!(:media_src), do: :ok def validate_directive!(:object_src), do: :ok def validate_directive!(:plugin_types), do: :ok + def validate_directive!(:prefetch_src), do: :ok def validate_directive!(:report_uri), do: :ok def validate_directive!(:sandbox), do: :ok def validate_directive!(:script_src), do: :ok + def validate_directive!(:script_src_attr), do: :ok + def validate_directive!(:script_src_elem), do: :ok def validate_directive!(:style_src), do: :ok + def validate_directive!(:style_src_elem), do: :ok + def validate_directive!(:webrtc), do: :ok + def validate_directive!(:worker_src), do: :ok def validate_directive!(directive) do raise ArgumentError, """ diff --git a/lib/content_security_policy/policy.ex b/lib/content_security_policy/policy.ex index fe6e7a6..f8dc2ed 100644 --- a/lib/content_security_policy/policy.ex +++ b/lib/content_security_policy/policy.ex @@ -12,7 +12,8 @@ defmodule ContentSecurityPolicy.Policy do @type t :: %Policy{} - defstruct child_src: nil, + defstruct base_uri: nil, + child_src: nil, connect_src: nil, default_src: nil, font_src: nil, @@ -20,12 +21,19 @@ defmodule ContentSecurityPolicy.Policy do frame_ancestors: nil, frame_src: nil, img_src: nil, + manifest_src: nil, media_src: nil, object_src: nil, plugin_types: nil, + prefetch_src: nil, report_uri: nil, sandbox: nil, script_src: nil, - style_src: nil + script_src_attr: nil, + script_src_elem: nil, + style_src: nil, + style_src_elem: nil, + webrtc: nil, + worker_src: nil end diff --git a/mix.exs b/mix.exs index 753621e..c879e8f 100644 --- a/mix.exs +++ b/mix.exs @@ -35,7 +35,7 @@ defmodule ContentSecurityPolicy.MixProject do {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.0.0-rc.7", only: [:dev], runtime: false}, {:ex_doc, "~> 0.21", only: :dev}, - {:mix_test_watch, "~> 0.6", only: :dev, runtime: false}, + {:mix_test_watch, "~> 1.0", only: :dev, runtime: false}, {:plug, "~> 1.1"}, {:order_invariant_compare, "~> 1.0.0", only: :test}, {:stream_data, ">= 0.0.0", only: :test}, diff --git a/mix.lock b/mix.lock index 354031c..171b58b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,19 +1,22 @@ %{ - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, - "credo": {:hex, :credo, "1.1.3", "bf31887b8914a4b7e1810ae2b5aab7c657698abbf4cca6a2335a094d57995168", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "dialyxir": {:hex, :dialyxir, "1.0.0-rc.7", "6287f8f2cb45df8584317a4be1075b8c9b8a69de8eeb82b4d9e6c761cf2664cd", [:mix], [{:erlex, ">= 0.2.5", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"}, - "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"}, - "erlex": {:hex, :erlex, "0.2.5", "e51132f2f472e13d606d808f0574508eeea2030d487fc002b46ad97e738b0510", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, - "mix_test_watch": {:hex, :mix_test_watch, "0.9.0", "c72132a6071261893518fa08e121e911c9358713f62794a90c95db59042af375", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"}, - "order_invariant_compare": {:hex, :order_invariant_compare, "1.0.0", "1b36603ccc01f098662cde92c7972387a93adfb16f1bcfbd1305e234b04aff84", [:mix], [], "hexpm"}, - "plug": {:hex, :plug, "1.8.3", "12d5f9796dc72e8ac9614e94bda5e51c4c028d0d428e9297650d09e15a684478", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, - "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, - "stream_data": {:hex, :stream_data, "0.4.3", "62aafd870caff0849a5057a7ec270fad0eb86889f4d433b937d996de99e3db25", [:mix], [], "hexpm"}, + "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, + "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"}, + "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"}, + "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm", "5e8806285d8a3a8999bd38e4a73c58d28534c856bc38c44818e5ba85bbda16fb"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "mix_test_watch": {:hex, :mix_test_watch, "1.1.0", "330bb91c8ed271fe408c42d07e0773340a7938d8a0d281d57a14243eae9dc8c3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "52b6b1c476cbb70fd899ca5394506482f12e5f6b0d6acff9df95c7f1e0812ec3"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, + "order_invariant_compare": {:hex, :order_invariant_compare, "1.0.0", "1b36603ccc01f098662cde92c7972387a93adfb16f1bcfbd1305e234b04aff84", [:mix], [], "hexpm", "e99a9f4c27c09edf6d951029719a84fa959b2df1188eb253427544d63683fdc3"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"}, + "stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"}, + "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, } diff --git a/test/content_security_policy/plug/add_nonce_test.exs b/test/content_security_policy/plug/add_nonce_test.exs index e071c23..0767f4d 100644 --- a/test/content_security_policy/plug/add_nonce_test.exs +++ b/test/content_security_policy/plug/add_nonce_test.exs @@ -16,7 +16,7 @@ defmodule ContentSecurityPolicy.Plug.AddNonceTest do |> send_resp(200, "ok") end - defp send_response_with_preset_nonce(add_nonce_plug_opts \\ [], preset_nonce) do + defp send_response_with_preset_nonce(add_nonce_plug_opts, preset_nonce) do :post |> conn("/foo") |> Map.merge(%{assigns: %{csp_nonce: preset_nonce}})