FEP-fe34: Origin-based security model

Another update: #593 - FEP-fe34: Reciprocal claims - fediverse/fep - Codeberg.org

I’ve added a new section titled “Reciprocal claims”. This is about bi-directional verification that we discussed earlier, the mechanism that enables trusted relationships across origins.

The description of the same-origin policy has been improved too:

Different origins are considered potentially hostile and are isolated from each other to varying degrees. Actors sharing an origin are assumed to trust each other because all their interactions are mediated by a single piece of software operated by a single person or an organization.

This part is still not universally true — multiple softwares can run on subdirectories of the same origin, where each prefix represents a trust boundary. Two actors on the same origin do not automatically authorize each other to perform actions against the other actor. The missing bit is that you can’t authenticate such identities without something like CIDs or DIDs — the TLS certificate is only valid for the origin. Similarly, another missing piece is that you should be able to make claims about prefixes and subresources.

I really feel like there should be guidance that basically taken to its logical conclusion, actors SHOULD have their own origins. Otherwise the security assumptions are invalid.

I agree, there are many ways to deploy and operate a server, and security boundaries dictated by the same-origin policy are somewhat arbitrary. But they are easy to enforce (because comparing origins is easy), and developers have a lot of experience with navigating them on the Web.

This FEP is developed in parallel with FEP-ef61 (Portable objects), where same-origin policy applies to DID-based identifiers.

A single DID authority may manage multiple actors.

Giving every actor an origin would be nice, but why assumptions are invalid otherwise? They can be invalid only if there exists an ActivityPub server that works differently. If that software product is important enough to make life harder for everyone else, then we can discuss how to change the requirements in the FEP.
But, as far as I know, the only software where actors can create arbitrary objects on the server is the one I am developing, and it does not invalidate the assumptions of the origin-based security model.

1 Like

There was another update several days ago: https://codeberg.org/fediverse/fep/pulls/653

The main change is stricter authentication rules for embedded objects.

More updates:

If the server allows clients to upload arbitrary files, it MUST serve media from a different origin (e.g. from a different subdomain).

This is an improvement that should limit the damage of same-origin assumption.

In some cases ownership might be implicit. Examples:

  • Inbox and outbox collections are expected to be owned by the actor to which they are attached.
  • A replies collection is owned by the actor to which the post is attributed.
  • All pages of a collection are expected to be owned by the same actor.

I think this is somewhat ambiguous because it could be argued that the server owns those collections, not the actor. There is some association between those collections, but it is not exactly “ownership”. Relatedly, FEP-5711 attempts to define “inverse properties” linking back to the actor or object without having to claim a direct attributedTo relationship. I am not completely sure if this is the best approach, but it does at least avoid the “ownership” ambiguity.

In any case, if this is to be called out in FEP-fe34, then probably it makes sense to call out the other collections (likes, shares, followers, following, liked) and not just replies.

Yes, more research is needed on the security properties of collections. Another unclear aspect is authentication of collection items, which is currently being discussed in another thread: Returning objects in a collection vs. IDs | ⁂ ActivityPub.Space

An embedded object can be trusted if it has the same origin and same owner as its parent: #698 - FEP-fe34: Update proposal - fediverse/fep - Codeberg.org

Update: https://codeberg.org/fediverse/fep/pulls/849

The FEP now discourages the use of partially embedded objects. I am not proposing an alternative yet, but pointing readers to this issue: https://codeberg.org/silverpill/feps/issues/21

Replied on #21 - [FEP-fe34]: Partially embedded objects - silverpill/feps - Codeberg.org

I think if someone applies an origin-based trust model then they need to rely more on the actual HTTP layer that makes use of the origin concept, not on the object layer which doesn’t.

The problem of “embedded descriptions” is not limited to whether they are “partial” (all descriptions are partial because there can always be more information not known to you). It’s also isomorphic to link previews and the thundering herd issue caused by basically all fedi servers choosing to independently verify OpenGraph information and basically never trusting it.

As @trwnh has mentioned, all objects must be considered partial. I also don’t see the connection with “trust”. Why would the partial representations be untrusted if it satisfies the trust criteria described in the FEP?

Note that different users fetching the same AP object can legitimately receive different representations of the object itself or of embedded objects depending on factors like authorization.

The relationship between application-level caching and the security model is not clear. This new recommendation is the only place caching is mentioned. What was the motivation for this change?

2 Likes

This statement doesn’t make any sense. Maybe it’s true for some other protocol, but I am talking about ActivityPub here.

I don’t remember saying that here, or in the FEP.

Partial objects may satisfy trust criteria and may be trusted by a consuming application. This is exactly the problem - see https://codeberg.org/silverpill/feps/issues/21.

So, no, this is not similar to link previews, which are not trusted.

It is allowed when collection items are filtered, but in general, it should be avoided. Buggy and malicious implementations are not the subject of this FEP.

No, it’s definitely ActivityPub. Both in theory and in practice.

If you don’t trust link previews, and you don’t trust embedded objects, and you have to fetch some canonical resource to verify the information given to you, then that’s the same shape of problem.

Any trust model applied to link previews could also be applied to embedded information and vice-versa. More generally, the question is “when/how can you trust information coming from non-canonical sources”, where “canonical source” is a representation of that https: URI obtained via HTTPS. The same-origin assumption extends this from “I trust the URI to talk about itself” to “I trust the Host to talk about any URI with the same scheme and whose authority component is the Host”[1]. If you apply this to embedded representations on the same origin, then why can’t you also apply this to link previews on the same origin?

  1. By default, https://domain.example/foo can make statements about https://domain.example/foo via Content
  2. With the same-origin assumption, domain.example can make statements about https://domain.example/foo via HTTPS
  3. With something like http://joinmastodon.org/ns#attributionDomains, eugenrochko.com and joinmastodon.org can be trusted to make attribution claims for https://mastodon.social/users/gargron via any attribution predicate/relationship/property/metadata/link.

One could continue to define additional clauses for establishing trust beyond these.


  1. Indeed, the same-origin assumption only works if you assume that an origin always represents the same entity. Multiple users on the same Host is a violation of the same-origin assumption, and leads to ambient authority issues. ↩︎

The question isn’t whether to trust an embedded object or not (I think it can be trusted in some cases specified in the FEP).

The question is, what to do if you trust an embedded object, but the author did not embed the full copy. You might get a small piece where just a few properties are present, but you might think it’s a complete object.

Here’s a contrived example:

{
  "id": "https://social.example/activities/update",
  "type": "Update",
  "actor": "https://social.example/alice",
  "object": {
    "id": "https://social.example/alice",
    "type": "Person"
   }
  "to": "https://social.example/bob"
}

Under normal circumstances, Bob is supposed to trust the embedded Person. But in this case it is a partial object, and if Bob accepts it as is, his connection to Alice might be severed because he lost her inbox.

So maybe Alice shouldn’t embed partial objects, after all. Or mark them somehow.

This is a problem with “full Update” semantics, not partial representations. (I think the best approach is to treat Update as “refetch the canonical resource” if you are interested in it from a caching perspective.)

Normally, I would say that <https://social.example/activities/update> is not the canonical resource for <https://social.example/alice>. If you want as much information about <https://social.example/alice> as you can GET, then you need to actually GET /alice. Otherwise, you work with what you are given. Either the information provided is enough to process, or it isn’t enough.

2 Likes