In this FEP I talk about the concept of ownership in ActivityPub network, and specify authentication and authorization procedures based on it.
Seems fine mostly, but the “first actor is the owner” doesn’t hold up technically. They’re unordered sets. It would be a mistake to make such assumptions based on ordering of the JSON presentation. We currently make the same mistake with the attachment array.
I’d prefer an extension (e.g., maybe an explicit owner
property?) rather than redefining existing terms.
In the Ownership section, you mention that AS2 defines some of the terms you are using, but then you use a variation of those definitions (or attributedTo
, for example). A section that describes differences with the AP/AS2 recs could be useful.
Every activity MUST have an
actor
property, which describes one or more entities that either performed or are expected to perform the activity. These entities MUST be actors and the first actor is considered the owner of the activity.
Any entity that is the subject of an actor
property is an actor, by definition. The MUST seems unnecessary.
True, but what could be done about it? The FEP may say that actor
and attributedTo
values MUST be a single actor, but multi-actor attributedTo
values are actually quite common, for example PeerTube uses them.
Yes, ideally it should be a new property, but actor
and attributedTo
are already used in the way described in this FEP. I think it wouldn’t hurt if we adjust definitions based on the implementation experience.
By variation, do you mean the removal of “The attributed entities might not be Actors” from the original definition?
I could add a note about that.
I’d like to keep that part for completeness.
That (which is significant), and the concept of a “first” item in the actor
and attributedTo
sets, and that attributedTo
is required for every object.
I was saying that it is complete without it. It probably doesn’t hurt to add redundant information, but it might raise questions about whether a specific point is being made.
I think you could say an activity is valid as long as it’s signed for by… any of? all of? the “owners”. That could be tricky to authenticate, but it’s where we are. The same issue arises for multiple inReplyTo
or multiple context
when paired with various control/authorization schemes.
I updated the proposal. Now it requires actor
and attributedTo
values to contain a single actor, and says in “Implementation notes” section that multiple owners are possible but not covered.
Diff: https://codeberg.org/fediverse/fep/commit/d62f5722801b5824af1464e845ac83785fcff4d4
It was fetched from the server that corresponds to the “origin” part of its owner’s ID.
I found an interesting edge case: object is served from a different subdomain. Traditional same origin policy would prohibit that. I think this FEP should also, if not prohibit then strongly recommend against this. For example, a different subdomain might be used for media uploads, and developer might fail to implement proper media type checks
Also, another interesting question, should object id
and its owner be of the same origin? Probably yes
if you wanted to treat all subdomains of a given DNS origin as equal (i.e. www.example.com
and asset-storage.example.com
or even the exotic {base32-CID}.ipfs-storage.example.com
, hehe) you could loosen this requirement to having the same apex domain rather than same origin, maybe?
So, I like the idea behind this FEP a lot! I think it formalizes a new property which adds a lot to the migration conversation, because migration is going to create a lot of new shades of grey between “authenticated” and “unauthenticated,” like “migrated content signed with keys that no longer resolve” and “content signed by keys that require particular trust models to verify”.
Steve’s suggestion that maybe owner
could or should be a new property rather than overloading existing terms is interesting, though. More generally, I’m a little confused on the upgrade path/legacy interop aspect here-- while this proposal could formalize the “owner” relationship going forward in a way, how do the implementations that don’t implement it co-exist with the ones that do? In particular, I was confused by the _MUST_s in the Authorization section:
If activity modifies or deletes the object, its owner MUST match the object’s owner.
Are there possible side-effects worth considering, such as a reply thread which includes some servers that DO implement this check (and thus drop an invalid delete request) and other servers that DON’T?
Also, does this mean that I can’t delete a post after migrating and importing it, because my actor id
has changed? Or does the destination server supporting Move Actor
and movedTo
mean the post-migration Actor effectively is the pre-migration Actor, for these purposes? If the latter, maybe this FEP “requires” FEP-7628 and it’s worth calling out the movedTo
redirect case?
Media is exactly the reason why I want to require full match rather than apex domain match. An attacker could upload malicious AP object as media and circumvent the same origin check, see GHSA-jhrq-qvrm-qr36. Obviously, implementers should verify the media type, but as a hardening measure, security researchers advised server operators to serve media from a different subdomain, and implementers to perform strict same-origin checks.
As far as I know, many existing implementations already perform checks described in this FEP. Those who don’t perform them are likely vulnerable to cache poisoning / impersonation attacks (although in some cases the severity of these vulnerabilities is low).
Servers that don’t implement this check will allow any actor to delete any cached object.
I don’t know, depends on the migration mechanism.
Updating the FEP to clarify the meaning of “origin”: #349 - FEP-c7d3: Update proposal - fediverse/fep - Codeberg.org
This PR also includes new requirements for collections (cc @trwnh).
Authorization of Delete
and Undo
activities: #380 - FEP-c7d3: Authorization of Delete and Undo activities - fediverse/fep - Codeberg.org
Delete
activity is special because moderators should be able to delete objects that were created on their server. Lemmy allows that (although apparently it goes further and allows deletion of remote objects too - that doesn’t make sense to me and is not compatible with FEP-c7d3).
Therefore, instead of the “same owner” check, recipients of Delete
activity should perform the “same origin” check. This reasoning can be applied to other activities too, because the real authority is server, not an actor, but I’d like to keep “same owner” recommendation for now.
Decided to change the “same owner” requirement to SHOULD and add a “same origin” requirement:
If activity modifies or deletes an object, its owner SHOULD match the object’s owner. If owners are different, their IDs MUST have the same origin.
I’m changing the requirement from “same owner” to “same origin” in “Authentication” and adding text about ownership of public keys / verification methods: #387 - FEP-c7d3: Update proposal - fediverse/fep - Codeberg.org
The owner of an object MUST be an actor. It MUST NOT change during the lifetime of an object.
This seems like it locks out some potential futures where “ownership” does indeed change. I’m not sure I’m comfy with the idea that ownership is non-transferable.
Also the same-origin check is not necessarily “enough” in all cases. I know that right now because of the way web origins work, you have to trust the web origin instead of trusting the individual actor, but there are potential cases where actors on the same origin do not in fact have control over the entire origin. Example: https://example.com/~alice
may have authority to create objects using the prefix https://example.com/~alice/
, but not within any other prefix (such as https://example.com/~bob/
or https://example.com/
). I don’t think there is a good way currently to express the “prefix” for which an actor has authority, is there?
Then this FEP needs to specify how ownership transfer happens. Is it an Update
activity? I think Update
can be used to transfer ownership within a web origin (i.e. when origin(object.id) == origin(object.attributedTo)
) . Transferring ownership to an actor on a different server probably shouldn’t be allowed.
Yes, the same-origin check is a minimal requirement, there might be additional application-specific constraints. I’ll clarify that in the text.
Even in this example, the owner of example.com
is still the highest authority who has the power to create and modify any object with any prefix. I think the internal prefix-based permission system used at example.com
can be expressed using extension properties (similarly to other permissions, e.g. reply permissions)
In the latest commit I added “Identifiers and ownership” and “Ownership transfer” sections:
Identifier of an object and identifier of its owner MUST have the same origin.
When ownership changes, the new owner ID MUST have the same origin as the old owner ID.
I have a few notes.
First, I don’t think it makes sense to say that the object is authentic. Rather, it’s safer to say that the ownership relationship is authentic.
Second, consider an ActivityPub API client that implements a drawing tool. You can create, update, and delete pictures. For an actor https://social.example/user/evan
, The client might push Create
activities into the actor’s outbox
like this:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"to": "as:Public",
"object": {
"type": "Image",
"id": "https://drawing.example/FJIhGP8Jp7CMWTO5hrjIW",
"url": {
"type": "Link",
"mediaType": "image/svg+xml",
"href": "https://drawing.example/files/5CvE73Yib6pDJXuZPaGaI.svg"
}
}
}
Fetching that drawing might return something like this:
{
"@context": "https://www.w3.org/ns/activitystreams",
"attributedTo": "https://social.example/user/evan",
"to": "as:Public",
"type": "Image",
"id": "https://drawing.example/FJIhGP8Jp7CMWTO5hrjIW",
"url": {
"type": "Link",
"mediaType": "image/svg+xml",
"href": "https://drawing.example/files/5CvE73Yib6pDJXuZPaGaI.svg"
}
}
This is an authentic ownership relationship, but the domains don’t match.
One way to confirm this ownership is by finding the Create
activity in the actor’s outbox
. That’s a linear search through a collection of O(10^5) or more, with pages of 20 or 100 items at a time. There’s an issue in AP for making this kind of search faster. membership endpoint · Issue #462 · w3c/activitypub · GitHub
Finally, I think you should change “MUST discard” to “MAY discard”. There may be other ways to determine the owner of an object, besides the one above or the ones listed – for example, a trust metric on the sending server. Leave it open to other uses.