HTTP header improvements (#294)
author@r3g_5z@plem.sapphic.site <june@terezi.dev>
Sun, 20 Nov 2022 21:20:06 +0000 (21:20 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Sun, 20 Nov 2022 21:20:06 +0000 (21:20 +0000)
- 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 (`<base>` 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 <june@terezi.dev>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/294
Co-authored-by: @r3g_5z@plem.sapphic.site <june@terezi.dev>
Co-committed-by: @r3g_5z@plem.sapphic.site <june@terezi.dev>
13 files changed:
config/config.exs
config/description.exs
docs/docs/configuration/cheatsheet.md
docs/docs/configuration/hardening.md
docs/docs/configuration/i2p.md
docs/docs/configuration/onion_federation.md
docs/docs/installation/openbsd_en.md
lib/pleroma/web/plugs/http_security_plug.ex
priv/gettext/ca/LC_MESSAGES/config_descriptions.po
priv/gettext/config_descriptions.pot
priv/gettext/es/LC_MESSAGES/config_descriptions.po
priv/gettext/nl/LC_MESSAGES/config_descriptions.po
test/pleroma/web/plugs/http_security_plug_test.exs

index ba77d8b021a67d6d7a4047a1cef201085ee2896e..f586e3883ef5270c928e0ac7b426b9609c45a93d 100644 (file)
@@ -487,8 +487,7 @@ config :pleroma, Pleroma.Web.Preload,
 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,
index 287abb747b8bcfb035b89d70f63574c137d917f1..b605bbd194f2ad53a17e50ef75afa125c905aaee 100644 (file)
@@ -1750,14 +1750,7 @@ config :pleroma, :config_description, [
         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,
index 49c37147dc8ceabc92b944f064c613577a0c9726..ee35d95bcf5d4509472baf61f657e399474b613e 100644 (file)
@@ -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.
 
index 3011812fc8d5f244f6242e0c967a0e12312f8dff..c5a9e160bc56646b79617723f2d2d5e75b9fc18c 100644 (file)
@@ -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`
index 981593366abdd56fa522c0f2105c99a578bc417e..ec6266ab7dc09ff85efe2a1550b6a77edab1cafa 100644 (file)
@@ -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;
index 9fc1cef062a57183b559fd175886a1f927646158..e4ae15fd292e6390315320501eeb6571952f83ea 100644 (file)
@@ -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;
index 2b163df6dfdcc5f88ba2fa860a79ff46d1b54659..9693467f281926a7a9603e3e52dc1c45be5c71cf 100644 (file)
@@ -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 "*"
index 5f36b77d166f217068db5d654ffd175d5dc53e94..47874a980147561439e1894a4bcddd2134edc4b3 100644 (file)
@@ -47,7 +47,6 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug 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 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug 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 @@ your instance and your users via malicious posts:
 
   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
 
index 3a25f067e45b9e929ea89fd5ed5a2d79462b8921..ad2177a9b171b8c5845125b5b06668851c91deaa 100644 (file)
@@ -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"
index 9021fbfab22f5cde6b976356ea9e1d9b9fb98a0f..1a55bfe68e19da4a3d03249f3f08f9881b00c3c8 100644 (file)
@@ -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"
index 9c1acae202210710d87336cf57e72a9b19b7d20e..f3602ce46025f5c882f0307430a40b78b5fd12b8 100644 (file)
@@ -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"
index 4def37366701d9f831be8a6bed8fc2aa1ade8dff..8ce06bf38e375eeee9c6246e01aff3df87fb2bb9 100644 (file)
@@ -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"
index 7f85f4a11352776c9f4555309c54241957eee4c7..d6d84107815896459bf6e78bebfe5c2b5e038f31 100644 (file)
@@ -17,7 +17,6 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest 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 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest 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 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest 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 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest 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