security: detect object containment violations at the IR level
authorAriadne Conill <ariadne@dereferenced.org>
Sun, 14 Jul 2019 17:47:08 +0000 (17:47 +0000)
committerAriadne Conill <ariadne@dereferenced.org>
Sun, 14 Jul 2019 17:47:08 +0000 (17:47 +0000)
It is more efficient to check for object containment violations at the IR
level instead of in the protocol handlers.  OStatus containment is especially
a tricky situation, as the containment rules don't match those of IR and
ActivityPub.

Accordingly, we just always do a final containment check at the IR level
before the object is added to the IR object graph.

lib/pleroma/object/containment.ex
lib/pleroma/web/activity_pub/activity_pub.ex
test/object/containment_test.exs

index ada9da0bb6de7a0bdcb144b789223b939bd5deb9..f077a9f32436841f1ffb01975c970d3082fd80a7 100644 (file)
@@ -48,6 +48,9 @@ defmodule Pleroma.Object.Containment do
     end
   end
 
+  def contain_origin(id, %{"attributedTo" => actor} = params),
+    do: contain_origin(id, Map.put(params, "actor", actor))
+
   def contain_origin_from_id(_id, %{"id" => nil}), do: :error
 
   def contain_origin_from_id(id, %{"id" => other_id} = _params) do
@@ -60,4 +63,9 @@ defmodule Pleroma.Object.Containment do
       :error
     end
   end
+
+  def contain_child(%{"object" => %{"id" => id, "attributedTo" => _} = object}),
+    do: contain_origin(id, object)
+
+  def contain_child(_), do: :ok
 end
index a3174a7871fc2f4d8188b26125ccf9ee8a832330..87963b691b8abafb9e7c001fb9488e4131039717 100644 (file)
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   alias Pleroma.Conversation
   alias Pleroma.Notification
   alias Pleroma.Object
+  alias Pleroma.Object.Containment
   alias Pleroma.Object.Fetcher
   alias Pleroma.Pagination
   alias Pleroma.Repo
@@ -126,6 +127,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
          {:ok, map} <- MRF.filter(map),
          {recipients, _, _} = get_recipients(map),
          {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
+         :ok <- Containment.contain_child(map),
          {:ok, map, object} <- insert_full_object(map) do
       {:ok, activity} =
         Repo.insert(%Activity{
index 1beed623646936ce43fd3bee76203ee119f2b640..61cd1b41228d896e72f4596789e331ce3e2a2f66 100644 (file)
@@ -68,4 +68,34 @@ defmodule Pleroma.Object.ContainmentTest do
                "[error] Could not decode user at fetch https://n1u.moe/users/rye, {:error, :error}"
     end
   end
+
+  describe "containment of children" do
+    test "contain_child() catches spoofing attempts" do
+      data = %{
+        "id" => "http://example.com/whatever",
+        "type" => "Create",
+        "object" => %{
+          "id" => "http://example.net/~alyssa/activities/1234",
+          "attributedTo" => "http://example.org/~alyssa"
+        },
+        "actor" => "http://example.com/~bob"
+      }
+
+      :error = Containment.contain_child(data)
+    end
+
+    test "contain_child() allows correct origins" do
+      data = %{
+        "id" => "http://example.org/~alyssa/activities/5678",
+        "type" => "Create",
+        "object" => %{
+          "id" => "http://example.org/~alyssa/activities/1234",
+          "attributedTo" => "http://example.org/~alyssa"
+        },
+        "actor" => "http://example.org/~alyssa"
+      }
+
+      :ok = Containment.contain_child(data)
+    end
+  end
 end