From 0e4c201f8dd607f5f34a247e63ab968204946052 Mon Sep 17 00:00:00 2001 From: "@r3g_5z@plem.sapphic.site" Date: Sun, 20 Nov 2022 21:20:06 +0000 Subject: [PATCH] HTTP header improvements (#294) - Drop Expect-CT Expect-CT has been redundant since 2018 when Certificate Transparency became mandated and required for all CAs and browsers. This header is only implemented in Chrome and is now deprecated. HTTP header analysers do not check this anymore as this is enforced by default. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT - Raise HSTS to 2 years and explicitly preload The longer age for HSTS, the better. Header analysers prefer 2 years over 1 year now as free TLS is very common using Let's Encrypt. For HSTS to be fully effective, you need to submit your root domain (domain.tld) to https://hstspreload.org. However, a requirement for this is the "preload" directive in Strict-Transport-Security. If you do not have "preload", it will reject your domain. - Drop X-Download-Options This is an IE8-era header when Adobe products used to use the IE engine for making outbound web requests to embed webpages in things like Adobe Acrobat (PDFs). Modern apps are using Microsoft Edge WebView2 or Chromium Embedded Framework. No modern browser checks or header analyser check for this. - Set base-uri to 'none' This is to specify the domain for relative links (`` HTML tag). pleroma-fe does not use this and it's an incredibly niche tag. I use all of these myself on my instance by rewriting the headers with zero problems. No breakage observed. I have not compiled my Elixr changes, but I don't see why they'd break. Co-authored-by: r3g_5z Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/294 Co-authored-by: @r3g_5z@plem.sapphic.site Co-committed-by: @r3g_5z@plem.sapphic.site --- config/config.exs | 3 +-- config/description.exs | 9 +-------- docs/docs/configuration/cheatsheet.md | 1 - docs/docs/configuration/hardening.md | 7 +------ docs/docs/configuration/i2p.md | 1 - docs/docs/configuration/onion_federation.md | 1 - docs/docs/installation/openbsd_en.md | 5 ++--- lib/pleroma/web/plugs/http_security_plug.ex | 7 ++----- priv/gettext/ca/LC_MESSAGES/config_descriptions.po | 12 ------------ priv/gettext/config_descriptions.pot | 12 ------------ priv/gettext/es/LC_MESSAGES/config_descriptions.po | 12 ------------ priv/gettext/nl/LC_MESSAGES/config_descriptions.po | 12 ------------ test/pleroma/web/plugs/http_security_plug_test.exs | 4 ---- 13 files changed, 7 insertions(+), 79 deletions(-) diff --git a/config/config.exs b/config/config.exs index ba77d8b02..f586e3883 100644 --- a/config/config.exs +++ b/config/config.exs @@ -487,8 +487,7 @@ config :pleroma, :http_security, enabled: true, sts: false, - sts_max_age: 31_536_000, - ct_max_age: 2_592_000, + sts_max_age: 63_072_000, referrer_policy: "same-origin" config :cors_plug, diff --git a/config/description.exs b/config/description.exs index 287abb747..b605bbd19 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1750,14 +1750,7 @@ label: "STS max age", type: :integer, description: "The maximum age for the Strict-Transport-Security header if sent", - suggestions: [31_536_000] - }, - %{ - key: :ct_max_age, - label: "CT max age", - type: :integer, - description: "The maximum age for the Expect-CT header if sent", - suggestions: [2_592_000] + suggestions: [63_072_000] }, %{ key: :referrer_policy, diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 49c37147d..ee35d95bc 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -453,7 +453,6 @@ This will make Akkoma listen on `127.0.0.1` port `8080` and generate urls starti * ``enabled``: Whether the managed content security policy is enabled. * ``sts``: Whether to additionally send a `Strict-Transport-Security` header. * ``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. * ``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. diff --git a/docs/docs/configuration/hardening.md b/docs/docs/configuration/hardening.md index 3011812fc..c5a9e160b 100644 --- a/docs/docs/configuration/hardening.md +++ b/docs/docs/configuration/hardening.md @@ -27,14 +27,13 @@ This will send additional HTTP security headers to the clients, including: * `X-Permitted-Cross-Domain-Policies: "none"` * `X-Frame-Options: "DENY"` * `X-Content-Type-Options: "nosniff"` -* `X-Download-Options: "noopen"` A content security policy (CSP) will also be set: ```csp content-security-policy: default-src 'none'; - base-uri 'self'; + base-uri 'none'; frame-ancestors 'none'; img-src 'self' data: blob: https:; media-src 'self' https:; @@ -52,10 +51,6 @@ content-security-policy: An additional “Strict transport security” header will be sent with the configured `sts_max_age` parameter. This tells the browser, that the domain should only be accessed over a secure HTTPs connection. -#### `ct_max_age` - -An additional “Expect-CT” header will be sent with the configured `ct_max_age` parameter. This enforces the use of TLS certificates that are published in the certificate transparency log. (see [Expect-CT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT)) - #### `referrer_policy` > Recommended value: `same-origin` diff --git a/docs/docs/configuration/i2p.md b/docs/docs/configuration/i2p.md index 981593366..ec6266ab7 100644 --- a/docs/docs/configuration/i2p.md +++ b/docs/docs/configuration/i2p.md @@ -160,7 +160,6 @@ server { add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Referrer-Policy same-origin; - add_header X-Download-Options noopen; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/docs/docs/configuration/onion_federation.md b/docs/docs/configuration/onion_federation.md index 9fc1cef06..e4ae15fd2 100644 --- a/docs/docs/configuration/onion_federation.md +++ b/docs/docs/configuration/onion_federation.md @@ -104,7 +104,6 @@ server { add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Referrer-Policy same-origin; - add_header X-Download-Options noopen; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/docs/docs/installation/openbsd_en.md b/docs/docs/installation/openbsd_en.md index 2b163df6d..9693467f2 100644 --- a/docs/docs/installation/openbsd_en.md +++ b/docs/docs/installation/openbsd_en.md @@ -165,10 +165,9 @@ http protocol plerup { # Protocol for upstream akkoma server match response header append "X-Frame-Options" value "DENY" match response header append "X-Content-Type-Options" value "nosniff" match response header append "Referrer-Policy" value "same-origin" - match response header append "X-Download-Options" value "noopen" - match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'self'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here + match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'none'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here match request header append "Connection" value "upgrade" - #match response header append "Strict-Transport-Security" value "max-age=31536000; includeSubDomains" # Uncomment this only after you get HTTPS working. + #match response header append "Strict-Transport-Security" value "max-age=63072000; includeSubDomains; preload" # Uncomment this only after you get HTTPS working. # If you do not want remote frontends to be able to access your Akkoma backend server, comment these lines match response header append "Access-Control-Allow-Origin" value "*" diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 5f36b77d1..47874a980 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -47,7 +47,6 @@ def headers do {"x-frame-options", "DENY"}, {"x-content-type-options", "nosniff"}, {"referrer-policy", referrer_policy}, - {"x-download-options", "noopen"}, {"content-security-policy", csp_string()}, {"permissions-policy", "interest-cohort=()"} ] @@ -76,7 +75,7 @@ def headers do static_csp_rules = [ "default-src 'none'", - "base-uri 'self'", + "base-uri 'none'", "frame-ancestors 'none'", "style-src 'self' 'unsafe-inline'", "font-src 'self'", @@ -237,11 +236,9 @@ def warn_if_disabled do defp maybe_send_sts_header(conn, true) do max_age_sts = Config.get([:http_security, :sts_max_age]) - max_age_ct = Config.get([:http_security, :ct_max_age]) merge_resp_headers(conn, [ - {"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains"}, - {"expect-ct", "enforce, max-age=#{max_age_ct}"} + {"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains; preload"} ]) end diff --git a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po index 3a25f067e..ad2177a9b 100644 --- a/priv/gettext/ca/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/ca/LC_MESSAGES/config_descriptions.po @@ -1936,12 +1936,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4993,12 +4987,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/config_descriptions.pot b/priv/gettext/config_descriptions.pot index 9021fbfab..1a55bfe68 100644 --- a/priv/gettext/config_descriptions.pot +++ b/priv/gettext/config_descriptions.pot @@ -1612,12 +1612,6 @@ msgctxt "config description at :pleroma-:http > :user_agent" msgid "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`." msgstr "" -#, elixir-autogen, elixir-format -#: lib/pleroma/docs/translator.ex:5 -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "" - #, elixir-autogen, elixir-format #: lib/pleroma/docs/translator.ex:5 msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4048,12 +4042,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "" -#, elixir-autogen, elixir-format -#: lib/pleroma/docs/translator.ex:5 -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "" - #, elixir-autogen, elixir-format #: lib/pleroma/docs/translator.ex:5 msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/es/LC_MESSAGES/config_descriptions.po b/priv/gettext/es/LC_MESSAGES/config_descriptions.po index 9c1acae20..f3602ce46 100644 --- a/priv/gettext/es/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/es/LC_MESSAGES/config_descriptions.po @@ -1759,12 +1759,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po index 4def37366..8ce06bf38 100644 --- a/priv/gettext/nl/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/nl/LC_MESSAGES/config_descriptions.po @@ -1759,12 +1759,6 @@ msgstr "" "What user agent to use. Must be a string or an atom `:default`. Default " "value is `:default`." -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config description at :pleroma-:http_security > :ct_max_age" -msgid "The maximum age for the Expect-CT header if sent" -msgstr "The maximum age for the Expect-CT header if sent" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config description at :pleroma-:http_security > :enabled" @@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent" msgid "User agent" msgstr "User agent" -#: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy -msgctxt "config label at :pleroma-:http_security > :ct_max_age" -msgid "CT max age" -msgstr "CT max age" - #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config label at :pleroma-:http_security > :enabled" diff --git a/test/pleroma/web/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs index 7f85f4a11..d6d841078 100644 --- a/test/pleroma/web/plugs/http_security_plug_test.exs +++ b/test/pleroma/web/plugs/http_security_plug_test.exs @@ -17,7 +17,6 @@ test "it sends CSP headers when enabled", %{conn: conn} do 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 @@ -28,7 +27,6 @@ test "it sends STS headers when enabled", %{conn: conn} do 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 @@ -37,7 +35,6 @@ test "it does not send STS headers when disabled", %{conn: conn} do 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 @@ -155,7 +152,6 @@ test "it does not send CSP headers when disabled", %{conn: conn} do assert Conn.get_resp_header(conn, "x-permitted-cross-domain-policies") == [] assert Conn.get_resp_header(conn, "x-frame-options") == [] assert Conn.get_resp_header(conn, "x-content-type-options") == [] - assert Conn.get_resp_header(conn, "x-download-options") == [] assert Conn.get_resp_header(conn, "referrer-policy") == [] assert Conn.get_resp_header(conn, "content-security-policy") == [] end