HTTP header improvements (#294)
ci/woodpecker/push/woodpecker Pipeline is pending Details

- 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: #294
Co-authored-by: @r3g_5z@plem.sapphic.site <june@terezi.dev>
Co-committed-by: @r3g_5z@plem.sapphic.site <june@terezi.dev>
pull/298/head
@r3g_5z@plem.sapphic.site 3 weeks ago committed by floatingghost
parent 6453297e9c
commit 0e4c201f8d

@ -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,

@ -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,

@ -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.

@ -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`

@ -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;

@ -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;

@ -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 "*"

@ -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

@ -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"

@ -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"

@ -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"

@ -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"

@ -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

Loading…
Cancel
Save