Fetching restricted remote activities

In ActivityPub you can have activities/actors/objects that need to be authenticated to fetch (to get url-referenced objects in the client, for example actors) and I was wondering how it should be done.

I can think of two ways it could be done:

  • via a proxying endpoint on your own server (not verified but maybe HTTP Proxy could simply be reused)
  • by fetching on the remote server (not a fan of that) via HTTP Signatures

cc: @yvolk

Currently, it’s not safe for servers to expose the private keys they use to sign activities to individual clients or users, so 1. is the only possible solution.

(there’s a DOS vulnerability if you let individual clients sign their own activities—they can create activities with an id on their own domain but matching the id of another user’s activity on the same domain, and prevent other servers from receiving that user’s activity)

@lanodan @nightpool In order for us all to understand the case, let’s start with a usage scenario.
As I understand, we could start with this:

  1. Client app is logged into Server1 as Actor1.

  2. Client app receives Activity1 from Server1. Activity1 refers ( inReplyTo ) to Activity2 on Server2 by URL2 (id) of that Activity2.

  3. Client app requests Activity2 object from its original URL2 without any authentication.

4.1. If Activity2 is publicly accessible, Server2 responds with the activity’s object.
4.1.1. Success

4.2. If Activity2 is NOT publicly accessible, Server2 responds with HTTP 403 error ?!
4.2.1. Client app needs another way to get Activity2.
4.2.2. ???

Are we talking about this?

[2020-05-06 18:51:48+0000] Yuri Volkov via SocialHub:

@lanodan @nightpool In order for us all to understand the case, let’s start with a usage scenario.
As I understand, we could start with this:

  1. Client app is logged into Server1 as Actor1.

  2. Client app receives Activity1 from Server1. Activity1 refers ( inReplyTo ) to Activity2 on Server2 by URL2 (id) of that Activity2.

  3. Client app requests Activity2 object from its original URL2 without any authentication.

4.1. If Activity2 is publicly accessible, Server2 responses with the activity’s object.
4.1.1. Success

4.2. If Activity2 is NOT publicly accessible, Server2 responses with HTTP 403 error ?!
4.2.1. Client app needs another way to get Activity2.
4.2.2. ???

Are we talking about this?

Yes, exactly this, with also the thing that I don’t think we should ever fetch from a foreign server so (4.1) shouldn’t be attempted. (privacy concerns but potentially security ones as well because you could use that for essentially turning the network into a http-get botnet, which we already quite have but with few limits)

:slight_smile: I wrote the whole scenario exactly in order to show that point 4.1. exists. My view is that ability for a client app to request (at least public…) resources directly from their sources is a key feature that ActivityPub C2S gives us. Please read also related thread CORS restrictions
@andstatus app actively uses this feature, which allows it to get information from the first hands, without a bottleneck of a server, to which app is logged in…

Regarding objects with restricted access, a client app could (as I see now…) also access Server2 directly using OAuth tokens obtained from Server1 (with authenticating Server1 having some trust relation with Server2… )

If you’re going to allow users to create IDs, you should isolate them so that they cannot collide. E.g., user bob can create activities with IDs in https://example.com/bob/activities and user alice can create activities with IDs in https://example.com/alice/activities. If alice tries to create an ID in bob's namespace, she gets Forbidden.

correct. that is not, however, a restriction the remote server can currently impose, because it has no knowledge of the origin server’s URI structure. Therefore, it is not safe to allow individual users access to the private keys tied to their actor on your server, since otherwise they would be able to bypass the ID creation requirements of your server.

OK, I think I’m caught up now. You’re imagining a scenario where there’s an activity with the id https://example.com/bob/123 on the example.com server, and that malicious actor Alice can create and sign a message with the same id and send it to another server, thereby corrupting its cache of the Activity with that id.

Since server developers cannot rely on other implementations not leaking private keys (intentionally or not), it would seem that this is a scenario that must be handled in any case. Therefore, servers should not trust the object they receive in the POST request, and should instead GET their own copy from the remote server, using the id of the Activity they received and the recipient’s signing key.

There are a number of weaknesses in the current model that will need to be addressed for this to work in the long term; you’ve identified a good one. I can imagine a resolution where the URL scope of the client key is included in the actor; but there should also be authentication that the message came from the server, so a PKI for servers should also be developed.

Basically we’re solving many of the same problems we have with email, which shouldn’t be very surprising since both systems are distributed, federated message systems.

Right now there are some efforts in Mastodon about removing the ability of fetching non-public objects at all, relying fully on getting those pushed: https://github.com/tootsuite/mastodon/pull/13584

I find stripping those relatively essential parts of ActivityPub away a bit concerning, although I can understand the point of complexity.
But I think before deciding to do so because of the lack of usage right now, it should at least be discussed in the protocol and implementers community.

So should I invite @ThibG over here?