HTTP header improvements (#294)
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
Some checks are pending
ci/woodpecker/push/woodpecker Pipeline is pending
- 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>
This commit is contained in:
parent
6453297e9c
commit
0e4c201f8d
13 changed files with 7 additions and 79 deletions
|
@ -487,8 +487,7 @@
|
||||||
config :pleroma, :http_security,
|
config :pleroma, :http_security,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
sts: false,
|
sts: false,
|
||||||
sts_max_age: 31_536_000,
|
sts_max_age: 63_072_000,
|
||||||
ct_max_age: 2_592_000,
|
|
||||||
referrer_policy: "same-origin"
|
referrer_policy: "same-origin"
|
||||||
|
|
||||||
config :cors_plug,
|
config :cors_plug,
|
||||||
|
|
|
@ -1750,14 +1750,7 @@
|
||||||
label: "STS max age",
|
label: "STS max age",
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "The maximum age for the Strict-Transport-Security header if sent",
|
description: "The maximum age for the Strict-Transport-Security header if sent",
|
||||||
suggestions: [31_536_000]
|
suggestions: [63_072_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]
|
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :referrer_policy,
|
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.
|
* ``enabled``: Whether the managed content security policy is enabled.
|
||||||
* ``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.
|
|
||||||
* ``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.
|
* ``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-Permitted-Cross-Domain-Policies: "none"`
|
||||||
* `X-Frame-Options: "DENY"`
|
* `X-Frame-Options: "DENY"`
|
||||||
* `X-Content-Type-Options: "nosniff"`
|
* `X-Content-Type-Options: "nosniff"`
|
||||||
* `X-Download-Options: "noopen"`
|
|
||||||
|
|
||||||
A content security policy (CSP) will also be set:
|
A content security policy (CSP) will also be set:
|
||||||
|
|
||||||
```csp
|
```csp
|
||||||
content-security-policy:
|
content-security-policy:
|
||||||
default-src 'none';
|
default-src 'none';
|
||||||
base-uri 'self';
|
base-uri 'none';
|
||||||
frame-ancestors 'none';
|
frame-ancestors 'none';
|
||||||
img-src 'self' data: blob: https:;
|
img-src 'self' data: blob: https:;
|
||||||
media-src 'self' 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.
|
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`
|
#### `referrer_policy`
|
||||||
|
|
||||||
> Recommended value: `same-origin`
|
> Recommended value: `same-origin`
|
||||||
|
|
|
@ -160,7 +160,6 @@ server {
|
||||||
add_header X-Frame-Options DENY;
|
add_header X-Frame-Options DENY;
|
||||||
add_header X-Content-Type-Options nosniff;
|
add_header X-Content-Type-Options nosniff;
|
||||||
add_header Referrer-Policy same-origin;
|
add_header Referrer-Policy same-origin;
|
||||||
add_header X-Download-Options noopen;
|
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
|
|
@ -104,7 +104,6 @@ server {
|
||||||
add_header X-Frame-Options DENY;
|
add_header X-Frame-Options DENY;
|
||||||
add_header X-Content-Type-Options nosniff;
|
add_header X-Content-Type-Options nosniff;
|
||||||
add_header Referrer-Policy same-origin;
|
add_header Referrer-Policy same-origin;
|
||||||
add_header X-Download-Options noopen;
|
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
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-Frame-Options" value "DENY"
|
||||||
match response header append "X-Content-Type-Options" value "nosniff"
|
match response header append "X-Content-Type-Options" value "nosniff"
|
||||||
match response header append "Referrer-Policy" value "same-origin"
|
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 '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 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 request header append "Connection" value "upgrade"
|
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
|
# 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 "*"
|
match response header append "Access-Control-Allow-Origin" value "*"
|
||||||
|
|
|
@ -47,7 +47,6 @@ def headers do
|
||||||
{"x-frame-options", "DENY"},
|
{"x-frame-options", "DENY"},
|
||||||
{"x-content-type-options", "nosniff"},
|
{"x-content-type-options", "nosniff"},
|
||||||
{"referrer-policy", referrer_policy},
|
{"referrer-policy", referrer_policy},
|
||||||
{"x-download-options", "noopen"},
|
|
||||||
{"content-security-policy", csp_string()},
|
{"content-security-policy", csp_string()},
|
||||||
{"permissions-policy", "interest-cohort=()"}
|
{"permissions-policy", "interest-cohort=()"}
|
||||||
]
|
]
|
||||||
|
@ -76,7 +75,7 @@ def headers do
|
||||||
|
|
||||||
static_csp_rules = [
|
static_csp_rules = [
|
||||||
"default-src 'none'",
|
"default-src 'none'",
|
||||||
"base-uri 'self'",
|
"base-uri 'none'",
|
||||||
"frame-ancestors 'none'",
|
"frame-ancestors 'none'",
|
||||||
"style-src 'self' 'unsafe-inline'",
|
"style-src 'self' 'unsafe-inline'",
|
||||||
"font-src 'self'",
|
"font-src 'self'",
|
||||||
|
@ -237,11 +236,9 @@ def warn_if_disabled do
|
||||||
|
|
||||||
defp maybe_send_sts_header(conn, true) do
|
defp maybe_send_sts_header(conn, true) do
|
||||||
max_age_sts = Config.get([:http_security, :sts_max_age])
|
max_age_sts = Config.get([:http_security, :sts_max_age])
|
||||||
max_age_ct = Config.get([:http_security, :ct_max_age])
|
|
||||||
|
|
||||||
merge_resp_headers(conn, [
|
merge_resp_headers(conn, [
|
||||||
{"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains"},
|
{"strict-transport-security", "max-age=#{max_age_sts}; includeSubDomains; preload"}
|
||||||
{"expect-ct", "enforce, max-age=#{max_age_ct}"}
|
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1936,12 +1936,6 @@ msgstr ""
|
||||||
"What user agent to use. Must be a string or an atom `:default`. Default "
|
"What user agent to use. Must be a string or an atom `:default`. Default "
|
||||||
"value is `: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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgctxt "config description at :pleroma-:http_security > :enabled"
|
msgctxt "config description at :pleroma-:http_security > :enabled"
|
||||||
|
@ -4993,12 +4987,6 @@ msgctxt "config label at :pleroma-:http > :user_agent"
|
||||||
msgid "User agent"
|
msgid "User agent"
|
||||||
msgstr "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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgctxt "config label at :pleroma-:http_security > :enabled"
|
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`."
|
msgid "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`."
|
||||||
msgstr ""
|
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
|
#, elixir-autogen, elixir-format
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
msgctxt "config description at :pleroma-:http_security > :enabled"
|
msgctxt "config description at :pleroma-:http_security > :enabled"
|
||||||
|
@ -4048,12 +4042,6 @@ msgctxt "config label at :pleroma-:http > :user_agent"
|
||||||
msgid "User agent"
|
msgid "User agent"
|
||||||
msgstr ""
|
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
|
#, elixir-autogen, elixir-format
|
||||||
#: lib/pleroma/docs/translator.ex:5
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
msgctxt "config label at :pleroma-:http_security > :enabled"
|
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 "
|
"What user agent to use. Must be a string or an atom `:default`. Default "
|
||||||
"value is `: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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgctxt "config description at :pleroma-:http_security > :enabled"
|
msgctxt "config description at :pleroma-:http_security > :enabled"
|
||||||
|
@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent"
|
||||||
msgid "User agent"
|
msgid "User agent"
|
||||||
msgstr "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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgctxt "config label at :pleroma-:http_security > :enabled"
|
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 "
|
"What user agent to use. Must be a string or an atom `:default`. Default "
|
||||||
"value is `: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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgctxt "config description at :pleroma-:http_security > :enabled"
|
msgctxt "config description at :pleroma-:http_security > :enabled"
|
||||||
|
@ -4420,12 +4414,6 @@ msgctxt "config label at :pleroma-:http > :user_agent"
|
||||||
msgid "User agent"
|
msgid "User agent"
|
||||||
msgstr "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
|
#: lib/pleroma/docs/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgctxt "config label at :pleroma-:http_security > :enabled"
|
msgctxt "config label at :pleroma-:http_security > :enabled"
|
||||||
|
|
|
@ -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-permitted-cross-domain-policies") == []
|
||||||
refute Conn.get_resp_header(conn, "x-frame-options") == []
|
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-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, "referrer-policy") == []
|
||||||
refute Conn.get_resp_header(conn, "content-security-policy") == []
|
refute Conn.get_resp_header(conn, "content-security-policy") == []
|
||||||
end
|
end
|
||||||
|
@ -28,7 +27,6 @@ test "it sends STS headers when enabled", %{conn: conn} do
|
||||||
conn = get(conn, "/api/v1/instance")
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
refute Conn.get_resp_header(conn, "strict-transport-security") == []
|
refute Conn.get_resp_header(conn, "strict-transport-security") == []
|
||||||
refute Conn.get_resp_header(conn, "expect-ct") == []
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not send STS headers when disabled", %{conn: conn} do
|
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")
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
assert Conn.get_resp_header(conn, "strict-transport-security") == []
|
assert Conn.get_resp_header(conn, "strict-transport-security") == []
|
||||||
assert Conn.get_resp_header(conn, "expect-ct") == []
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "referrer-policy header reflects configured value", %{conn: conn} do
|
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-permitted-cross-domain-policies") == []
|
||||||
assert Conn.get_resp_header(conn, "x-frame-options") == []
|
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-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, "referrer-policy") == []
|
||||||
assert Conn.get_resp_header(conn, "content-security-policy") == []
|
assert Conn.get_resp_header(conn, "content-security-policy") == []
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue