w3c / activitypub

http://w3c.github.io/activitypub/
Other
1.2k stars 77 forks source link

How are Actor Endpoints provideClientKey and signClientKey supposed to work? #382

Open yretenai opened 1 year ago

yretenai commented 1 year ago

ActivityPub currently specifies two Actor endpoints, provideClientKey and signClientKey and I'm a bit lost how it's meant to be implemented.

The other endpoints all have some indication what kind of data is expected both on the client and server, but those two are vague.

Is it left to the implementation to define how client keys are provided and signed?

evanp commented 1 year ago

Wow! This is some interesting specification archaeology.

As far as I can tell, these two properties were added to support an old version from 2016 of Linked Data Signatures for client authentication.

I can't find a good example of using these two properties for client-to-server authentication. I will continue looking and see if we can identify one.

My strong recommendation at this point is to avoid using these properties unless you specifically are wanting to support Linked Data Signatures.

If you are trying to use client authentication, OAuth 2.0 with bearer tokens probably a much better choice.

evanp commented 1 year ago

@cwebber do you remember what happened with these properties? Any guesses for example code that uses them?

evanp commented 1 year ago

I did a massive GitHub search and didn't find a satisfying usage https://github.com/search?q=provideClientKey&type=code

yretenai commented 1 year ago

My strong recommendation at this point is to avoid using these properties unless you specifically are wanting to support Linked Data Signatures. If you are trying to use client authentication, OAuth 2.0 with bearer tokens probably a much better choice.

Well, I normally would agree completely however in the scenario I am interested in this wouldn't quite work. In this scenario a client would request specific activity objects from a remote server directly (i.e. not the home server.)

We would be required to sign requests to fetch private posts, and in the case of Authorized Fetch (a mode introduced with I believe Mastodon) where even public read requests need to be signed. The OAuth route doesn't quite work with remote servers unless the entire OAuth grant is federated (which would be a gigantic pain.)

So Linked Data Signatures are the only route, unless ZCAP gets formally finalized (and more importantly implemented)

dmitrizagidulin commented 1 year ago

@yretenai - I'm also really interested in fetching private posts! Would you like to collaborate on a FEP (or just like a post)?

unless the entire OAuth grant is federated (which would be a gigantic pain.)

I absolutely agree with you - OAuth 2 for the case of fetching private / friend-only posts is not really scalable. The two things I was going to suggest are - zCaps (which you already know about -- and they've been out there in production, though in non-Fedi context, for years now). (And zCaps do use HTTP Signatures, for actual authorized calls). The other (possibly main) thing I'd recommend, is UCANs (basically isomorphic to zCaps, though not linked data). UCANs also support proof-of-possession during invocation, like zCaps, but I don't think they use HTTP Sig, they use another DPoP mechanism.

navi-desu commented 1 year ago

@dmitrizagidulin @yretenai

nyahello

we want to build servers and clients that talk via activitypub's c2s instead of platform specific apis. so mainly clients posting to the users outbox as a way to federate, and loading one's "feed" from their inbox.

one issue occurs when the client wants to load a post tho, that is, how to authenticate that client as on behalf of the user to remote servers, which would be needed for restricted posts (dm/follower's only)

the current consideration for this is zcap, but i have a slight worry that all zcap's features may be a bit of an overkill for this, since keeping it simple is should also be a concern (especially considering how the adoption of json-ld on activitypub software, well, basically isn't as of right now)

although i hope to simplify this situation for implementers by writing a couple libs, libactivity-server and libactivity-client, hopefully abstracting most of this away.

making this authorization concept a fed would be interesting to help standardization, so i do have interest in that too!

nightpool commented 1 year ago

We would be required to sign requests to fetch private posts, and in the case of Authorized Fetch (a mode introduced with I believe Mastodon) where even public read requests need to be signed

this would not be sound given the current security system, under no situation should HTTP Signature keys be provided to end users, since that would allow for several types of URI exhaustion / DOS vulnerabilities

The correct way to implement multiuser Authorized Fetch is to provide a proxy endpoints where the client authenticates itself to its local server, which can then authenticate itself in turn to the remote server. This is already necessary for e.g. CORS reasons.

yretenai commented 1 year ago

ZCAP defines a specification that delegates privileges to other components while the caveats are still valid.

In this instance the server would be delegating read permissions to an actor's key, the server's keys and even the end user's keys are not compromised. You're essentially creating a cross signed request, with zcap providing the data graph to define what the concerns should be-- only the server can set this up.

Which is why I was looking into provideClientKey and signClientKey, it's entirely possible for the server to create a new timed certificate that only lasts, say an hour that's signed with the user's private key. The original key would still be secret to the user.

From what I understand ZCAP would make this less implicit and more verbose, with more granularity in how it expires or gets revoked-- but the spec is still early in development.

As for CORS, most ActivityPub implementations already correctly define the Access-Control headers (Mastodon does not, but nearly every other platform does.)

There is also the proxyUrl actor endpoint which would cover the cases you're describing, and for cases where a user wants to proxy everything through their home server. C2S would only bypass the home server's third party API, POSTing would still be made to your own local outbox. If I comprehended the spec correctly, only servers can POST to inboxes.

navi-desu commented 1 year ago

this would not be sound given the current security system, under no situation should HTTP Signature keys be provided to end users, since that would allow for several types of URI exhaustion / DOS vulnerabilities

if i'm not mistaken, as @yretenai posted, that is one of the things zcap is meant to solve, whereas the cryptographic key is in the linked data document, and the user's home server is used as a validator for those keys (correct me if i understood zcap wrong, please)

The correct way to implement multiuser Authorized Fetch is to provide a proxy endpoints where the client authenticates itself to its local server, which can then authenticate itself in turn to the remote server

the problem with this is basically performance, you now are always forced to make two requests per request, one from you to your server, another from your server to the remote server. ideally

dmitrizagidulin commented 1 year ago

@nightpool

this would not be sound given the current security system, under no situation should HTTP Signature keys be provided to end users, since that would allow for several types of URI exhaustion / DOS vulnerabilities

I'm curious what you mean by URI exhaustion / DOS, with respect to HTTP Sig. Can you say more?

yretenai commented 1 year ago

I'm curious what you mean by URI exhaustion / DOS, with respect to HTTP Sig. Can you say more?

If I understand the problem correctly, it's due to how Authorized Fetch is implemented (or rather, how LD Signatures are verified.)

It will validate the LD Signature with the remote key indiscriminately, rather than verifying if the key has the correct permissions. The same keys can be used universally, for both read and write requests.

This normally would be fine in a pure S2S environment, but if we delegate new keys to the user for C2S Read purposes they could in theory submit requests into the inbox with malformed data because the keys have unlimited power. This means that clients can create posts for object IRIs that don't exist. Normally, this would be immediately deleted as the home server would respond with a 410 or 404 error but that could submit unwanted load to the server, but many implementations skip the resolve step.

I should mention that in the spec there's a section specifically for verification, and many implementations assume LD Signature verification is valid for the whole scope.

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.

dmitrizagidulin commented 1 year ago

@yretenai Ahhh yeah ok, that part's bad :) (and fixable)

dmitrizagidulin commented 1 year ago

I should mention that in the spec there's a section specifically for verification, and many implementations assume LD Signature verification is valid for the whole scope.

Yeah, this is /exactly/ why HTTP Signatures alone are insufficient for this. At best, they have to be paired with zCaps or something like UCANs.

yretenai commented 1 year ago

I think the HTTP Signature can be enough, as currently we're providing a keyId value, that hopefully points to a JSON-LD object with a https://w3id.org/security#Key on a publicKey term. This would harden it against misuse with client keys.

The issue is that we'd need to add a scope (or similar) term on top of this key class, and hope that major instances refactor their codebase to support multiple keys.

The idea me and @navi-desu had in mind is:

Which is why I was asking about what provideClientKey and signClientKey are, because that seems like an important detail.

silverpill commented 1 year ago

@yretenai

The issue is that we'd need to add a scope (or similar) term on top of this key class, and hope that major instances refactor their codebase to support multiple keys.

There's a Fediverse Enhancement Proposal (FEP) for supporting multiple public keys per actor: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md. It's doesn't use publicKey property so implementers may start publishing multiple keys without breaking compatibility with existing software. It also provides a way to specify key purpose (perhaps this is what you meant by scope?).

navi-desu commented 1 year ago

There's a Fediverse Enhancement Proposal (FEP) for supporting multiple public keys per actor: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md.

this kinda works but we would need for it to have it's own fetch id outside the Actor object, because the user itself might be under authorized fetch, so two servers that don't have each other's keys cached, could get into a deadlock of recursively resolving keys

It also provides a way to specify key purpose (perhaps this is what you meant by scope?).

yeah, this is what we have in mind. the scope is just to differentiate a server's key, used to sign federated data that goes into user's inboxes, from client's keys, used only to fetch data

silverpill commented 11 months ago

I wrote a FEP that introduces two endpoints similar to provideClientKey and signClientKey:

https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md

The endpoints are registerIdentity and verifyIdentity, and they are meant to be discovered using well-known URL, not using actor object. That provides a simple way to create an actor and sign activities and objects on the client side.

nightpool commented 11 months ago

Why use a well-known URL? that goes against all of the existing ActivityPub protocol design, which is centered around actor documents (so that many different types of actor software could coexist on the same origin)

On Tue, Oct 3, 2023, 3:11 AM silverpill @.***> wrote:

I wrote a FEP that introduces two endpoints similar to provideClientKey and signClientKey:

https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md

The endpoints are registerIdentity and verifyIdentity, and they are meant to be discovered using well-known URL, not using actor object. That provides a simple way to create an actor and sign activities and objects on the client side.

— Reply to this email directly, view it on GitHub https://github.com/w3c/activitypub/issues/382#issuecomment-1744429773, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABZCV55VJ2QPJLOTJNDGRDX5PCC3AVCNFSM6AAAAAA24Q4HT2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONBUGQZDSNZXGM . You are receiving this because you were mentioned.Message ID: @.***>

navi-desu commented 11 months ago

I wrote a FEP that introduces two endpoints similar to provideClientKey and signClientKey:

https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md

The endpoints are registerIdentity and verifyIdentity, and they are meant to be discovered using well-known URL, not using actor object. That provides a simple way to create an actor and sign activities and objects on the client side.

if i got this right, this doesn't really help on what we need, that is authorization on fetch/get. this seems made to ensure communication between a client and the homeserver when creating an activity. which is nice, but what we're looking for here is ensure that a client is authorized to get a private resource (followers only post, for example) from a remote server, which doesn't involve sending a body, so all we have to work with would be the HTTP Signature


also, i also don't see why use .well-known, when we can use make actor extensions instead.

silverpill commented 11 months ago

At the beginning actor doesn't exist, and client should use registerIdentity endpoint (discovered via .well-known URL) to create it (per FEP-ae97). Is there a better way?

ap-socialhub commented 8 months ago

This issue has been mentioned on SocialHub. There might be relevant details there:

https://socialhub.activitypub.rocks/t/documentation-or-examples-about-proxyurl-provideclientkey-and-signclientkey-endpoints/2089/6

jernst commented 8 months ago

I note that none of the Actor files we collect at https://fedidevs.org/reference/actor/ use either of them.

evanp commented 3 months ago

@yretenai I think you should use proxyUrl instead. Much easier!