security: detect object containment violations at the IR level

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.
This commit is contained in:
Ariadne Conill 2019-07-14 17:47:08 +00:00
parent 93701c3399
commit 739bbe0d3b
3 changed files with 40 additions and 0 deletions

View file

@ -48,6 +48,9 @@ def contain_origin(id, %{"actor" => _actor} = params) do
end end
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" => nil}), do: :error
def contain_origin_from_id(id, %{"id" => other_id} = _params) do def contain_origin_from_id(id, %{"id" => other_id} = _params) do
@ -60,4 +63,9 @@ def contain_origin_from_id(id, %{"id" => other_id} = _params) do
:error :error
end end
end end
def contain_child(%{"object" => %{"id" => id, "attributedTo" => _} = object}),
do: contain_origin(id, object)
def contain_child(_), do: :ok
end end

View file

@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Conversation alias Pleroma.Conversation
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Object.Fetcher alias Pleroma.Object.Fetcher
alias Pleroma.Pagination alias Pleroma.Pagination
alias Pleroma.Repo alias Pleroma.Repo
@ -126,6 +127,7 @@ def insert(map, local \\ true, fake \\ false) when is_map(map) do
{:ok, map} <- MRF.filter(map), {:ok, map} <- MRF.filter(map),
{recipients, _, _} = get_recipients(map), {recipients, _, _} = get_recipients(map),
{:fake, false, map, recipients} <- {:fake, fake, map, recipients}, {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
:ok <- Containment.contain_child(map),
{:ok, map, object} <- insert_full_object(map) do {:ok, map, object} <- insert_full_object(map) do
{:ok, activity} = {:ok, activity} =
Repo.insert(%Activity{ Repo.insert(%Activity{

View file

@ -68,4 +68,34 @@ test "users cannot be collided through fake direction spoofing attempts" do
"[error] Could not decode user at fetch https://n1u.moe/users/rye, {:error, :error}" "[error] Could not decode user at fetch https://n1u.moe/users/rye, {:error, :error}"
end end
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 end