Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85829802
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex
index 6462797b6..f9aff2fab 100644
--- a/lib/pleroma/plugs/http_security_plug.ex
+++ b/lib/pleroma/plugs/http_security_plug.ex
@@ -1,151 +1,159 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Plugs.HTTPSecurityPlug do
alias Pleroma.Config
import Plug.Conn
require Logger
def init(opts), do: opts
def call(conn, _options) do
if Config.get([:http_security, :enabled]) do
conn
|> merge_resp_headers(headers())
|> maybe_send_sts_header(Config.get([:http_security, :sts]))
else
conn
end
end
defp headers do
referrer_policy = Config.get([:http_security, :referrer_policy])
report_uri = Config.get([:http_security, :report_uri])
headers = [
{"x-xss-protection", "1; mode=block"},
{"x-permitted-cross-domain-policies", "none"},
{"x-frame-options", "DENY"},
{"x-content-type-options", "nosniff"},
{"referrer-policy", referrer_policy},
{"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)}]
+ [{"reply-to", Jason.encode!(report_group)} | headers]
else
headers
end
end
+ @csp_start [
+ "default-src 'none'",
+ "base-uri 'self'",
+ "frame-ancestors 'none'",
+ "style-src 'self' 'unsafe-inline'",
+ "font-src 'self'",
+ "manifest-src 'self'"
+ ]
+ |> Enum.join(";")
+ |> Kernel.<>(";")
+ |> List.wrap()
+
defp csp_string do
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
static_url = Pleroma.Web.Endpoint.static_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, ?\s, websocket_url]
connect_src =
if Pleroma.Config.get(:env) == :dev do
- connect_src <> " http://localhost:3035/"
+ [connect_src," http://localhost:3035/"]
else
connect_src
end
script_src =
if Pleroma.Config.get(:env) == :dev do
"script-src 'self' 'unsafe-eval'"
else
"script-src 'self'"
end
- main_part = [
- "default-src 'none'",
- "base-uri 'self'",
- "frame-ancestors 'none'",
- "img-src 'self' data: blob: https:",
- "media-src 'self' https:",
- "style-src 'self' 'unsafe-inline'",
- "font-src 'self'",
- "manifest-src 'self'",
- connect_src,
- script_src
- ]
-
- report = if report_uri, do: ["report-uri #{report_uri}; report-to csp-endpoint"], else: []
+ report = if report_uri, do: ["report-uri ", report_uri, ";report-to csp-endpoint"]
+ insecure = if scheme == "https", do: "upgrade-insecure-requests"
+
+ @csp_start
+ |> add_csp_param("img-src 'self' data: blob: https:")
+ |> add_csp_param("media-src 'self' https:")
+ |> add_csp_param(connect_src)
+ |> add_csp_param(script_src)
+ |> add_csp_param(insecure)
+ |> add_csp_param(report)
+ |> :erlang.iolist_to_binary()
+ end
- insecure = if scheme == "https", do: ["upgrade-insecure-requests"], else: []
+ defp add_csp_param(csp_iodata, nil), do: csp_iodata
- (main_part ++ report ++ insecure)
- |> Enum.join("; ")
- end
+ defp add_csp_param(csp_iodata, param), do: [[param, ?;] | csp_iodata]
def warn_if_disabled do
unless Config.get([:http_security, :enabled]) do
Logger.warn("
.i;;;;i.
iYcviii;vXY:
.YXi .i1c.
.YC. . in7.
.vc. ...... ;1c.
i7, .. .;1;
i7, .. ... .Y1i
,7v .6MMM@; .YX,
.7;. ..IMMMMMM1 :t7.
.;Y. ;$MMMMMM9. :tc.
vY. .. .nMMM@MMU. ;1v.
i7i ... .#MM@M@C. .....:71i
it: .... $MMM@9;.,i;;;i,;tti
:t7. ..... 0MMMWv.,iii:::,,;St.
.nC. ..... IMMMQ..,::::::,.,czX.
.ct: ....... .ZMMMI..,:::::::,,:76Y.
c2: ......,i..Y$M@t..:::::::,,..inZY
vov ......:ii..c$MBc..,,,,,,,,,,..iI9i
i9Y ......iii:..7@MA,..,,,,,,,,,....;AA:
iIS. ......:ii::..;@MI....,............;Ez.
.I9. ......:i::::...8M1..................C0z.
.z9; ......:i::::,.. .i:...................zWX.
vbv ......,i::::,,. ................. :AQY
c6Y. .,...,::::,,..:t0@@QY. ................ :8bi
:6S. ..,,...,:::,,,..EMMMMMMI. ............... .;bZ,
:6o, .,,,,..:::,,,..i#MMMMMM#v................. YW2.
.n8i ..,,,,,,,::,,,,.. tMMMMM@C:.................. .1Wn
7Uc. .:::,,,,,::,,,,.. i1t;,..................... .UEi
7C...::::::::::::,,,,.. .................... vSi.
;1;...,,::::::,......... .................. Yz:
v97,......... .voC.
izAotX7777777777777777777777777777777777777777Y7n92:
.;CoIIIIIUAA666666699999ZZZZZZZZZZZZZZZZZZZZ6ov.
HTTP Security is disabled. Please re-enable it to prevent users from attacking
your instance and your users via malicious posts:
config :pleroma, :http_security, enabled: true
")
end
end
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}"}
])
end
defp maybe_send_sts_header(conn, _), do: conn
end
diff --git a/test/plugs/http_security_plug_test.exs b/test/plugs/http_security_plug_test.exs
index 84e4c274f..63b4d3f31 100644
--- a/test/plugs/http_security_plug_test.exs
+++ b/test/plugs/http_security_plug_test.exs
@@ -1,92 +1,92 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
use Pleroma.Web.ConnCase
alias Pleroma.Config
alias Plug.Conn
setup do: clear_config([:http_securiy, :enabled])
setup do: clear_config([:http_security, :sts])
setup do: clear_config([:http_security, :referrer_policy])
describe "http security enabled" do
setup do
Config.put([:http_security, :enabled], true)
end
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;|
+ 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
test "it does not send CSP headers when disabled", %{conn: conn} do
Config.put([:http_security, :enabled], false)
conn = get(conn, "/api/v1/instance")
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-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
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Nov 1, 12:35 AM (18 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1801981
Default Alt Text
(10 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline