Origin checking between servers
-
@oplik0 and I are having a discussion regarding the conditions upon which origin checking should be done on S2S activity receipt.
The spec says this:
Servers should not trust client submitted content, and federated servers also should not trust content received from a server other than the content's origin without some form of verification.
Reasonable, if a little open-ended. I took this to mean that if an
Activity(Object)
is received, ifObject
is a copy of the resource itself, that origin checking is required. This is reflected currently in the NodeBB code where iftypeof object !== 'string'
then origin check is carried out.Problem is, that's a code smell. It's not readily apparent why an origin check is only carried out under that condition. Compounding this is that not all activities need an origin check:
Create
,Update
, andDelete
typically don't (careful in my wording here, lest I say something way off-base).@oplik0 advocates for a more explicit approach, where perhaps an object uri is dereferenced regardless, and an origin check is carried out if the specific
Activity-Object
type pair calls for it (and if the uri doesn't match).P.S. Yes, @[email protected] I know
object
can also be an Array... or undefined... or null... don't @ me!) -
Jason Culverhouse :flipboard:replied to julian on last edited by
> some form of verification
You verify the "origin" by validating the HTTP Signature on the request and that it is signed by a key that belongs to the `actor` in the activity.
If the `actor` that signed the HTTP request is different than the `actor` of the activity you verify the content via the JSON-LD signature on the activity and that the signature signing key belongs to the `actor` of the activity.
-
@julian
The verification can be fetching it by ID, but it doesn't have to be. I think you can trust that objects you receive that are attributed to the actor and hosted at the same authority as the actor are valid. More generally, you should have some authorization mechanisms for federated activities. -
@[email protected] Are JSON-LD signatures implemented broadly? Mastodon's docs state the following in a warning box:
... the LD Signatures specification as a whole has been superseded by the Verifiable Credential Data Integrity 1.0 specification, which is largely incompatible with the earlier LD Signature spec. For this reason, it is not advised to implement support for LD Signatures.
I'll admit I do not know whether there has been an effort by SWICG to compile a descriptive report on the state of security in ActivityPub implementors, but I would be interested in learning more.
-
@[email protected] said:
I think you can trust that objects you receive that are attributed to the actor and hosted at the same authority as the actor are valid.
I think that's fair. If I recall correctly the main concern was Activity spoofing by third parties (e.g. Receiving
Update(Note)
from domainA for a Note whose origin hostname is domainB).Each individual code path does their own checking if needed, so in the example above,
Update
handling actually does origin checking too (since the passed-inobject
is a uri, and thus not subject to checking via upstream middleware), but now that is a case of DRY.Question is, what activity-pairs explicitly need origin checking... or conversely, is a deny-list a better fit? (e.g.
Announce(Note)
can refer to Notes outside of the actor origin, so don't do an origin check) -
Erin π½β¨replied to julian on last edited by [email protected]@julian @jenniferplusplus *every* path needs an authority check
In the case of Announce(Note), where the Note is from a different origin from the authenticating key, you should fetch it rather than trusting the embedded object -
@julian isn't there also a FEP for object signatures? e.g., signing the Activity as a whole with the Actor's private key? (I can't recall the trade-offs here)
-
@julian @jenniferplusplus one option is just walking the tree of objects and every time you find an object with an id from a different origin than the http signature key, replace it with the result of fetching
-
@[email protected] @[email protected]
I believe that would be @[email protected]'s FEP-8b32?
-
@jenniferplusplus @julian (alternatively just replace them with stubs and fetch lazily if needed)
-
@julian yup.
-
@[email protected] Yes, I think that's what @oplik0 and I ended up agreeing on. If we normalize all incoming requests so that any requests containing a full object on a different domain is just reduced down to its id, then you'd safeguard yourself from most edge cases. Applying FEP-8b32 would be handy to save yourself a few network calls but is optional.
The cost is you might have to make a couple extra calls, but it's probably worth it in order to keep the logic simple, predictable, and easily auditable.