Authorized Fetch and the Instance Actor

Using an instance actor for mitigating the authorized fetch key retrieval bug seems strange to me so I dug into the historical record to try to understand how this all evolved. Clarifications, corrections or additional information are welcome (with references, please).

From looking at the history of this topic (AP issue tracker, Mastodon issue tracker, IRC chats), it looks like the root cause of these issues is the “#main-key” URI fragment, which caused the key and profile to effectively be effectively the same dereferenced document (although different resources).

The “#main-key” fragment was included in an example from the ActivityPub community, which was inspired by the LD Signature README. Mastodon devs then merged support based on that example in 2017. There was no discussion about authorized fetch issues at the time because it wasn’t added to Mastodon until 2019. Initially, with authorized fetch enabled, the public key and a few other profile properties would be returned (to avoid the sig verification ping-pong bug).

Actors can still be fetched without signature, but return only technical attributes

The “technical details” included the public key information. A Pleroma developer suggested using an “instance actor” for this purpose (“mitigation”), but that wasn’t immediately implemented by the Mastodon team.

In Pleroma, we plan on using an instance-specific actor to represent the fetches for this mitigation.

Later, the Mastodon team restricted all access to regular account profiles. They noted:

This isn’t really an improvement in security, as the only information that was previously returned was required protocol-level info, and the only personal bit was the existence of the account. The existence of the account can still be checked by issuing a webfinger query, as those are accepted without signatures.

If I understand the comments correctly, the primary motivation was protecting other instances from storing the limited actor profiles after an unsigned fetch in authorized fetch mode.

However, this change makes it so that unallowed instances won’t create account records on their end when they find a reference to an unknown account.

By that time, the Mastodon team had added an “instance actor” for other purposes, so they decided to use the mitigation the Pleroma developer has previously suggested.

This feels like a Fediverse bug to me that could have been avoided by allowing the actor’s public key resource to be dereferenced separately, and without verifying a signature, from the actor profile document. For example, it looks like making the key URI something like https://server.example/actor/bob/main-key instead of https://server.example/actor/bob#main-key could have prevented several (maybe all?) of these issues.

1 Like

When activity arrives to a personal inbox, any outgoing GET requests (e.g. fetching sender’s profile) may be signed by the recipient.
When activity arrives to a shared inbox, the server is the recipient, so you have to use application actor to sign outgoing requests.

Also, fragment IDs are actually very important. When you verify a HTTP signature on incoming activity you probably want a complete actor profile, but HTTP signature only contains key ID. When key and actor have different locations, the recipient of activity needs to make two requests: fetch the key, and then fetch the actor. By using fragment IDs we reduce the number of requests by half, which is significant improvement because signature verification is often done synchronously and therefore becomes a performance bottleneck.

1 Like

Mastodon doesn’t appear to require fragment-based key ids for incoming requests and is able to load signature key documents independently from the actor profile (in the non-fragment case). I can provide more details on this, if anyone is interested.

Why do you need a complete actor profile just to verify a signature for a remote actor fetching a local profile?

I understand the performance optimization point when you do need both. However, caching the keys, similar to how most instances cache actor profiles, can reduce the number of remote requests after the first interaction. Also, an implementation could try to fetch an actor+key first and then fall back to the key fetch for signature validation if the former fails because of authorized fetch issues.

Social applications require full profiles, so it makes sense to fetch full profiles right away. Separation of keys and profiles just adds unnecessary complexity.

There’s no bug, instance actor is a useful construction and authorized fetch is not the only reason why it exists.

I suppose one person’s bug is another person’s feature. In any case, I’m only discussing an “instance actor” being used to mitigate the authorized profile fetch problem for signature verification. Whether it’s useful for other purposes is a different topic of discussion.

@trwnh posted a good summary of some of the issues associated with using the “instance actor” in the context of authorized profile (and other content?) fetches.

By “locations”, I assume you mean separate JSON-LD documents. I’d expect that servers would still want to use “same origin” policies for public key and the owner/entity profile URIs.

Digging into this more, I think the performance argument is not a strong one in favor proxy actors for authorized fetch (often implemented by an “instance actor”). Although this would vary by implementation, Mastodon does several other requests associated with new remote profile fetch (followers, following, outbox, …) so this wouldn’t double the number of requests for that scenario. The extra request only happens during that initial profile fetch. After that, the public key will be cached locally for subsequent signature verifications.

I think the overhead of the extra fetch is negligible compared to the benefits. However, I’m still not clear about the expected benefit of the current “authorized fetch” behavior, so I may be missing something. I can see it potentially supporting domain blocking, but it seems like that could be done based on the key URI without signature verification. In other words, if the key URI domain is blocked then why check the request signature?

Does Mastodon fetch followers, following and outbox during signature verification? Seems unlikely. These tasks can be performed later, in background.

Signature verification is a performance bottleneck, and every request matters. Check out this post: SIF-2023-001 – SiliconForest Advisory

That’s a good point. I’d guess at least some of those are background requests. The only HTTP request that’s logically required for synchronous signature verification is the public key request (and only when it’s not already cached).

Aren’t you mixing several topics here? There’s a performance cost to signature verification, even when the keys are cached and no HTTP request is required. And there’s the relatively small number of requests needed to exchange public keys and then cache them. Assuming this happens when a new remote account record is created in my server, that would be ~70/day median for the last year. It’s not obvious that every request matters in this case. There are always tradeoffs involved (see the previous discussion of privacy and moderation issues related to using instance/proxy actors to bypass authorized fetch restrictions, for example).

The advisory is interesting, but I don’t see how it’s relevant. Yes, creating many simultaneously requests and delaying PK (or WebFinger) responses for 20 seconds may cause problems. I’m not proposing either. :wink:

It’s interesting that the advisory recommends doing signature verification asynchronously, which may address your concern about public key retrieval during that operation. However, from a developer perspective, I like the synchronous handling for HTTP error reporting purposes (although I know there are other, asynchronous, AP error reporting possibilities being discussed).