Discuss: Signed Fetches and Redirects #731

Open
opened 2024-04-02 02:02:55 +00:00 by Oneric · 0 comments
Member

When we fetch AP objects we sign the initial request¹ using the URL we’re fetching from. (At least when :activitypub, :sign_object_fetches is enabled, but i presume no production server disables it.) But before we actually receive the object we may follow redirects which change the URL, yet we never change the request signature. This means we can end up fetching with a signature not actually valid for the final URL.

An example of such redirects are indeed our very own status display URLs https://instance.example/notice/CreateActivityID which first redirect to the canonical location of the not e object https://instance.example/objects/some-unrelated-uid. In theory other server implementations or alternative frontends may also set up redirects.

In practice we can easily see fetching other Akkoma display URLs does in fact work, but it’s not because we somehow resign after all, but because when verifying the signature, we currently generate a list of all known aliases and accept if the signature is valid for any of them. Other implementations may also not be lenient about signatures for aliases.

def route_aliases(%{path_info: ["objects", id], query_string: query_string}) do
ap_id = url(~p[/objects/#{id}])
with %Activity{} = activity <- Activity.get_by_object_ap_id_with_object(ap_id) do
[~p"/notice/#{activity.id}", "/notice/#{activity.id}?#{query_string}"]
else
_ -> []
end
end

  def route_aliases(%{path_info: ["objects", id], query_string: query_string}) do
    ap_id = url(~p[/objects/#{id}])

    with %Activity{} = activity <- Activity.get_by_object_ap_id_with_object(ap_id) do
      [~p"/notice/#{activity.id}", "/notice/#{activity.id}?#{query_string}"]
    else
      _ -> []
    end
  end

This seems a bit iffy to me and constitutes a coupling between front- and backend since only aliases known to the backend can be used in frontends as display URLs. It also makes verification more costly since we need to query the database for the related Create activity.
In an ideal setup, we’d both resign our fetches on redirects and not ponder any aliases during verification.

In practice stopping to permit any aliases during verification comes with some struggles though.

Variants with and without query parameters are both considered due to a disagreement between spec and Mastodon’s implementation practice on whether signatures should include them. Mastodon never includes them while spec requires inclusion and historically GTS strictly adhered to spec. Now, GTS will attempt both versions preferring the variant with query parameters included.

Furthermore, I’m told Misskey and Mastodon currently also never resign their fetches on redirects. Presumably this is why they directly serve AP objects under their display URL instead of redirecting to its canonical location. With “directly serve AP” being their workaround for a missing resign instead of our “accept signatures for any alias”.
Unless we’re willing to break lookup of Akkoma posts by search on Mastodon and Misskey-derivatives, we probably also can’t drop aliases unrelated to query-parameters.

Leaving resigning our own requests on redirects as the only currently viable improvement. If noone else is known to do redirects and we need to keep accepting aliases anyway though, this calls into question whether this is actually useful (apart from a faint hope of future Mastodon/Misskey improvements and an agreement wrt query parameters)

Welp, I titled this “Discuss” but there isn’t really any open points to discuss and it turned more into a documentation/lamenting of why things are the way they are.
If you have any further insight, strong opinions or know of other implementations which either employs redirects or resign its requests on encountering redirects this might change things though (if nothing else to at least motivate resigning our own requests)

When we fetch AP objects we sign the initial request¹ using the URL we’re fetching from. *(At least when `:activitypub, :sign_object_fetches` is enabled, but i presume no production server disables it.)* But before we actually receive the object we may follow redirects which change the URL, yet we never change the request signature. This means we can end up fetching with a signature not actually valid for the final URL. An example of such redirects are indeed our very own status display URLs `https://instance.example/notice/CreateActivityID` which first redirect to the canonical location of the not e object `https://instance.example/objects/some-unrelated-uid`. In theory other server implementations or alternative frontends may also set up redirects. In practice we can easily see fetching other Akkoma display URLs does in fact work, but it’s not because we somehow resign after all, but because when verifying the signature, we currently generate a list of all known aliases and accept if the signature is valid for any of them. Other implementations may also not be lenient about signatures for aliases. https://akkoma.dev/AkkomaGang/akkoma/src/commit/2d439034ca801b704536cb05483e012d62c2d52e/lib/pleroma/web/plugs/http_signature_plug.ex#L35-L43 ```elixir def route_aliases(%{path_info: ["objects", id], query_string: query_string}) do ap_id = url(~p[/objects/#{id}]) with %Activity{} = activity <- Activity.get_by_object_ap_id_with_object(ap_id) do [~p"/notice/#{activity.id}", "/notice/#{activity.id}?#{query_string}"] else _ -> [] end end ``` This seems a bit iffy to me and constitutes a coupling between front- and backend since only aliases known to the backend can be used in frontends as display URLs. It also makes verification more costly since we need to query the database for the related Create activity. In an ideal setup, we’d both resign our fetches on redirects and not ponder any aliases during verification. In practice stopping to permit any aliases during verification comes with some struggles though. Variants with and without query parameters are both considered due to a disagreement between spec and Mastodon’s implementation practice on whether signatures should include them. Mastodon never includes them while spec requires inclusion and historically GTS strictly adhered to spec. Now, GTS will [attempt both versions](https://docs.gotosocial.org/en/latest/federation/federating_with_gotosocial/#query-parameters) preferring the variant with query parameters included. Furthermore, I’m told Misskey and Mastodon currently also never resign their fetches on redirects. Presumably this is why they directly serve AP objects under their display URL instead of redirecting to its canonical location. With *“directly serve AP”* being their workaround for a missing resign instead of our *“accept signatures for any alias”*. Unless we’re willing to break lookup of Akkoma posts by search on Mastodon and Misskey-derivatives, we probably also can’t drop aliases unrelated to query-parameters. Leaving resigning our own requests on redirects as the only currently viable improvement. If noone else is known to do redirects and we need to keep accepting aliases anyway though, this calls into question whether this is actually useful *(apart from a faint hope of future Mastodon/Misskey improvements and an agreement wrt query parameters)* Welp, I titled this “Discuss” but there isn’t really any open points to discuss and it turned more into a documentation/lamenting of why things are the way they are. If you have any further insight, strong opinions or know of other implementations which either employs redirects or resign its requests on encountering redirects this might change things though *(if nothing else to at least motivate resigning our own requests)*
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: AkkomaGang/akkoma#731
No description provided.