forked from AkkomaGang/akkoma
add report uri and report to
This commit is contained in:
parent
62516be9c4
commit
aa11fa4864
5 changed files with 107 additions and 65 deletions
|
@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Configuration: `fetch_initial_posts` option
|
- Configuration: `fetch_initial_posts` option
|
||||||
- Configuration: `notify_email` option
|
- Configuration: `notify_email` option
|
||||||
- Configuration: Media proxy `whitelist` option
|
- Configuration: Media proxy `whitelist` option
|
||||||
|
- Configuration: `report_uri` option
|
||||||
- Pleroma API: User subscriptions
|
- Pleroma API: User subscriptions
|
||||||
- Pleroma API: Healthcheck endpoint
|
- Pleroma API: Healthcheck endpoint
|
||||||
- Admin API: Endpoints for listing/revoking invite tokens
|
- Admin API: Endpoints for listing/revoking invite tokens
|
||||||
|
|
|
@ -61,6 +61,8 @@
|
||||||
|
|
||||||
config :pleroma, :app_account_creation, max_requests: 5
|
config :pleroma, :app_account_creation, max_requests: 5
|
||||||
|
|
||||||
|
config :pleroma, :http_security, report_uri: "https://endpoint.com"
|
||||||
|
|
||||||
try do
|
try do
|
||||||
import_config "test.secret.exs"
|
import_config "test.secret.exs"
|
||||||
rescue
|
rescue
|
||||||
|
|
|
@ -286,7 +286,8 @@ This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls start
|
||||||
* ``sts``: Whether to additionally send a `Strict-Transport-Security` header
|
* ``sts``: Whether to additionally send a `Strict-Transport-Security` header
|
||||||
* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent
|
* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent
|
||||||
* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent
|
* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent
|
||||||
* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"`.
|
* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"`
|
||||||
|
* ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header.
|
||||||
|
|
||||||
## :mrf_user_allowlist
|
## :mrf_user_allowlist
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,9 @@ def call(conn, _options) do
|
||||||
|
|
||||||
defp headers do
|
defp headers do
|
||||||
referrer_policy = Config.get([:http_security, :referrer_policy])
|
referrer_policy = Config.get([:http_security, :referrer_policy])
|
||||||
|
report_uri = Config.get([:http_security, :report_uri])
|
||||||
|
|
||||||
[
|
headers = [
|
||||||
{"x-xss-protection", "1; mode=block"},
|
{"x-xss-protection", "1; mode=block"},
|
||||||
{"x-permitted-cross-domain-policies", "none"},
|
{"x-permitted-cross-domain-policies", "none"},
|
||||||
{"x-frame-options", "DENY"},
|
{"x-frame-options", "DENY"},
|
||||||
|
@ -30,12 +31,27 @@ defp headers do
|
||||||
{"x-download-options", "noopen"},
|
{"x-download-options", "noopen"},
|
||||||
{"content-security-policy", csp_string() <> ";"}
|
{"content-security-policy", csp_string() <> ";"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if report_uri do
|
||||||
|
report_group = %{
|
||||||
|
"group" => "csp-endpoint",
|
||||||
|
"max-age" => 10_886_400,
|
||||||
|
"endpoints" => [
|
||||||
|
%{"url" => report_uri}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
headers ++ [{"reply-to", Jason.encode!(report_group)}]
|
||||||
|
else
|
||||||
|
headers
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp csp_string do
|
defp csp_string do
|
||||||
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
|
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
|
||||||
static_url = Pleroma.Web.Endpoint.static_url()
|
static_url = Pleroma.Web.Endpoint.static_url()
|
||||||
websocket_url = Pleroma.Web.Endpoint.websocket_url()
|
websocket_url = Pleroma.Web.Endpoint.websocket_url()
|
||||||
|
report_uri = Config.get([:http_security, :report_uri])
|
||||||
|
|
||||||
connect_src = "connect-src 'self' #{static_url} #{websocket_url}"
|
connect_src = "connect-src 'self' #{static_url} #{websocket_url}"
|
||||||
|
|
||||||
|
@ -53,7 +69,7 @@ defp csp_string do
|
||||||
"script-src 'self'"
|
"script-src 'self'"
|
||||||
end
|
end
|
||||||
|
|
||||||
[
|
main_part = [
|
||||||
"default-src 'none'",
|
"default-src 'none'",
|
||||||
"base-uri 'self'",
|
"base-uri 'self'",
|
||||||
"frame-ancestors 'none'",
|
"frame-ancestors 'none'",
|
||||||
|
@ -63,11 +79,14 @@ defp csp_string do
|
||||||
"font-src 'self'",
|
"font-src 'self'",
|
||||||
"manifest-src 'self'",
|
"manifest-src 'self'",
|
||||||
connect_src,
|
connect_src,
|
||||||
script_src,
|
script_src
|
||||||
if scheme == "https" do
|
|
||||||
"upgrade-insecure-requests"
|
|
||||||
end
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
report = if report_uri, do: ["report-uri #{report_uri}; report-to csp-endpoint"], else: []
|
||||||
|
|
||||||
|
insecure = if scheme == "https", do: ["upgrade-insecure-requests"], else: []
|
||||||
|
|
||||||
|
(main_part ++ report ++ insecure)
|
||||||
|> Enum.join("; ")
|
|> Enum.join("; ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,28 +7,89 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
|
||||||
test "it sends CSP headers when enabled", %{conn: conn} do
|
describe "http security enabled" do
|
||||||
Config.put([:http_security, :enabled], true)
|
setup do
|
||||||
|
enabled = Config.get([:http_securiy, :enabled])
|
||||||
|
|
||||||
conn =
|
Config.put([:http_security, :enabled], true)
|
||||||
conn
|
|
||||||
|> get("/api/v1/instance")
|
|
||||||
|
|
||||||
refute Conn.get_resp_header(conn, "x-xss-protection") == []
|
on_exit(fn ->
|
||||||
refute Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == []
|
Config.put([:http_security, :enabled], enabled)
|
||||||
refute Conn.get_resp_header(conn, "x-frame-options") == []
|
end)
|
||||||
refute Conn.get_resp_header(conn, "x-content-type-options") == []
|
|
||||||
refute Conn.get_resp_header(conn, "x-download-options") == []
|
:ok
|
||||||
refute Conn.get_resp_header(conn, "referrer-policy") == []
|
end
|
||||||
refute Conn.get_resp_header(conn, "content-security-policy") == []
|
|
||||||
|
test "it sends CSP headers when enabled", %{conn: conn} do
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
refute Conn.get_resp_header(conn, "x-xss-protection") == []
|
||||||
|
refute Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == []
|
||||||
|
refute Conn.get_resp_header(conn, "x-frame-options") == []
|
||||||
|
refute Conn.get_resp_header(conn, "x-content-type-options") == []
|
||||||
|
refute Conn.get_resp_header(conn, "x-download-options") == []
|
||||||
|
refute Conn.get_resp_header(conn, "referrer-policy") == []
|
||||||
|
refute Conn.get_resp_header(conn, "content-security-policy") == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it sends STS headers when enabled", %{conn: conn} do
|
||||||
|
Config.put([:http_security, :sts], true)
|
||||||
|
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
refute Conn.get_resp_header(conn, "strict-transport-security") == []
|
||||||
|
refute Conn.get_resp_header(conn, "expect-ct") == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it does not send STS headers when disabled", %{conn: conn} do
|
||||||
|
Config.put([:http_security, :sts], false)
|
||||||
|
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
assert Conn.get_resp_header(conn, "strict-transport-security") == []
|
||||||
|
assert Conn.get_resp_header(conn, "expect-ct") == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "referrer-policy header reflects configured value", %{conn: conn} do
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
assert Conn.get_resp_header(conn, "referrer-policy") == ["same-origin"]
|
||||||
|
|
||||||
|
Config.put([:http_security, :referrer_policy], "no-referrer")
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> get("/api/v1/instance")
|
||||||
|
|
||||||
|
assert Conn.get_resp_header(conn, "referrer-policy") == ["no-referrer"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it sends `report-to` & `report-uri` CSP response headers" do
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> get("/api/v1/instance")
|
||||||
|
|
||||||
|
[csp] = Conn.get_resp_header(conn, "content-security-policy")
|
||||||
|
|
||||||
|
assert csp =~ ~r|report-uri https://endpoint.com; report-to csp-endpoint;|
|
||||||
|
|
||||||
|
[reply_to] = Conn.get_resp_header(conn, "reply-to")
|
||||||
|
|
||||||
|
assert reply_to ==
|
||||||
|
"{\"endpoints\":[{\"url\":\"https://endpoint.com\"}],\"group\":\"csp-endpoint\",\"max-age\":10886400}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not send CSP headers when disabled", %{conn: conn} do
|
test "it does not send CSP headers when disabled", %{conn: conn} do
|
||||||
|
enabled = Config.get([:http_securiy, :enabled])
|
||||||
|
|
||||||
Config.put([:http_security, :enabled], false)
|
Config.put([:http_security, :enabled], false)
|
||||||
|
|
||||||
conn =
|
on_exit(fn ->
|
||||||
conn
|
Config.put([:http_security, :enabled], enabled)
|
||||||
|> get("/api/v1/instance")
|
end)
|
||||||
|
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
assert Conn.get_resp_header(conn, "x-xss-protection") == []
|
assert Conn.get_resp_header(conn, "x-xss-protection") == []
|
||||||
assert Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == []
|
assert Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == []
|
||||||
|
@ -38,46 +99,4 @@ test "it does not send CSP headers when disabled", %{conn: conn} do
|
||||||
assert Conn.get_resp_header(conn, "referrer-policy") == []
|
assert Conn.get_resp_header(conn, "referrer-policy") == []
|
||||||
assert Conn.get_resp_header(conn, "content-security-policy") == []
|
assert Conn.get_resp_header(conn, "content-security-policy") == []
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it sends STS headers when enabled", %{conn: conn} do
|
|
||||||
Config.put([:http_security, :enabled], true)
|
|
||||||
Config.put([:http_security, :sts], true)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> get("/api/v1/instance")
|
|
||||||
|
|
||||||
refute Conn.get_resp_header(conn, "strict-transport-security") == []
|
|
||||||
refute Conn.get_resp_header(conn, "expect-ct") == []
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it does not send STS headers when disabled", %{conn: conn} do
|
|
||||||
Config.put([:http_security, :enabled], true)
|
|
||||||
Config.put([:http_security, :sts], false)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> get("/api/v1/instance")
|
|
||||||
|
|
||||||
assert Conn.get_resp_header(conn, "strict-transport-security") == []
|
|
||||||
assert Conn.get_resp_header(conn, "expect-ct") == []
|
|
||||||
end
|
|
||||||
|
|
||||||
test "referrer-policy header reflects configured value", %{conn: conn} do
|
|
||||||
Config.put([:http_security, :enabled], true)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> get("/api/v1/instance")
|
|
||||||
|
|
||||||
assert Conn.get_resp_header(conn, "referrer-policy") == ["same-origin"]
|
|
||||||
|
|
||||||
Config.put([:http_security, :referrer_policy], "no-referrer")
|
|
||||||
|
|
||||||
conn =
|
|
||||||
build_conn()
|
|
||||||
|> get("/api/v1/instance")
|
|
||||||
|
|
||||||
assert Conn.get_resp_header(conn, "referrer-policy") == ["no-referrer"]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue