From a953b1d9279a4c87d0a26885477a65f939892df9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 May 2024 19:08:37 +0100 Subject: [PATCH] Prevent spoofing webfinger --- lib/pleroma/web/web_finger.ex | 18 +++++++++ test/fixtures/tesla_mock/bad.com_host_meta | 3 ++ test/fixtures/tesla_mock/webfinger_spoof.json | 28 +++++++++++++ test/pleroma/web/web_finger_test.exs | 39 ++++++++++++------- 4 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 test/fixtures/tesla_mock/bad.com_host_meta create mode 100644 test/fixtures/tesla_mock/webfinger_spoof.json diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 9d5efbb3e..eeb186ce7 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -217,10 +217,28 @@ def finger(account) do _ -> {:error, {:content_type, nil}} end + |> case do + {:ok, data} -> validate_webfinger(address, data) + error -> error + end + else error -> Logger.debug("Couldn't finger #{account}: #{inspect(error)}") error end end + + defp validate_webfinger(url, %{"subject" => "acct:" <> acct} = data) do + with %URI{host: request_host} <- URI.parse(url), + [_name, acct_host] <- String.split(acct, "@"), + {_, true} <- {:hosts_match, acct_host == request_host} do + {:ok, data} + else + _ -> {:error, {:webfinger_invalid, url, data}} + end + end + + defp validate_webfinger(url, data), do: {:error, {:webfinger_invalid, url, data}} + end diff --git a/test/fixtures/tesla_mock/bad.com_host_meta b/test/fixtures/tesla_mock/bad.com_host_meta new file mode 100644 index 000000000..14cf3fa24 --- /dev/null +++ b/test/fixtures/tesla_mock/bad.com_host_meta @@ -0,0 +1,3 @@ + + + diff --git a/test/fixtures/tesla_mock/webfinger_spoof.json b/test/fixtures/tesla_mock/webfinger_spoof.json new file mode 100644 index 000000000..ebe2958ce --- /dev/null +++ b/test/fixtures/tesla_mock/webfinger_spoof.json @@ -0,0 +1,28 @@ +{ + "aliases": [ + "https://bad.com/users/meanie", + "https://anotherbad.social/users/meanie" + ], + "links": [ + { + "href": "https://bad.com/users/meanie", + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html" + }, + { + "href": "https://bad.com/users/meanie", + "rel": "self", + "type": "application/activity+json" + }, + { + "href": "https://bad.com/users/meanie", + "rel": "self", + "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" + }, + { + "rel": "http://ostatus.org/schema/1.0/subscribe", + "template": "https://bad.com/ostatus_subscribe?acct={uri}" + } + ], + "subject": "acct:oopsie@notwhereitshouldbe.org" +} diff --git a/test/pleroma/web/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs index b47eabe80..141bb9d6a 100644 --- a/test/pleroma/web/web_finger_test.exs +++ b/test/pleroma/web/web_finger_test.exs @@ -76,15 +76,6 @@ test "returns the ActivityPub actor URI for an ActivityPub user" do {:ok, _data} = WebFinger.finger(user) end - test "returns the ActivityPub actor URI and subscribe address for an ActivityPub user with the ld+json mimetype" do - user = "kaniini@gerzilla.de" - - {:ok, data} = WebFinger.finger(user) - - assert data["ap_id"] == "https://gerzilla.de/channel/kaniini" - assert data["subscribe_address"] == "https://gerzilla.de/follow?f=&url={uri}" - end - test "it work for AP-only user" do user = "kpherox@mstdn.jp" @@ -99,12 +90,6 @@ test "it work for AP-only user" do assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}" end - test "it works for friendica" do - user = "lain@squeet.me" - - {:ok, _data} = WebFinger.finger(user) - end - test "it gets the xrd endpoint" do {:ok, template} = WebFinger.find_lrdd_template("social.heldscal.la") @@ -180,5 +165,29 @@ test "respects xml content-type" do {:ok, _data} = WebFinger.finger("pekorino@pawoo.net") end + + test "prevents spoofing" do + Tesla.Mock.mock(fn + %{ + url: "https://bad.com/.well-known/webfinger?resource=acct:meanie@bad.com" + } -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/webfinger_spoof.json"), + headers: [{"content-type", "application/jrd+json"}] + }} + + %{url: "https://bad.com/.well-known/host-meta"} -> + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/bad.com_host_meta") + }} + end) + + {:error, _data} = WebFinger.finger("meanie@bad.com") + end + end end