BREAKING: activitypub: validate fetch signatures #399
Loading…
Reference in a new issue
No description provided.
Delete branch "helene/FoundKey:feature/verify-fetch-signatures"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Enforces HTTP signatures on object fetches, and rejects fetches from blocked instances. This should mean proper and full blocking of remote instances.
This is now default behavior, which makes it a breaking change.
To disable it (mostly for development purposes),
allowUnsignedFetches
can be set totrue
in the configuration . It is not the default for development environments as it is important to have as close as possible behavior to real environments for ActivityPub development.Co-authored-by: nullobsi
Co-authored-by: Norm
Changelog: Added
The points below are things to refactor which are more notes to myself. Of course feel free to apply some of the suggestions.
However something that should be at least thought about before this is merged: This is only somewhat effective at hiding the content. You can obviously still see it in the frontend, scrape it from the API or from
<meta>
opengraph tags.@ -85,0 +85,4 @@
@Column('boolean', {
default: false
})
public allowUnsignedFetches: boolean;
🔧 I think it would be better if this goes into the config file instead of the database. People should not have to manually edit the database to change configuration.
@ -59,6 +61,30 @@ export function setResponseType(ctx: Router.RouterContext): void {
}
}
export function handleSignatureResult(ctx: Router.RouterContext, result: SignatureValidationResult): boolean {
This function is always used together with
validateFetchSignature
, and the call signature is alwayshandleSignatureResult(ctx, await validateFetchSignature(ctx.req))
. Is there a reason for them being two separate functions?It would seem sensible to either combine these functions or at least put the function call inside. This reduces the number of parameters and makes it easier to read.
It could be easier to understand if this was a middleware function that could be added to routes.
I don't think this function needs to be
export
ed since it isn't used in other modules/files.The
export
is a mistake, yes. I thought that it would be easier to implement a feature to allow users to block specific instances from accessing their activities, if it was done this way, but having a unifiedhandleSignature
shouldn't be a problem for this situation; it would only mean adding a new argument in such a case, which would actually be preferable. I will apply your suggestion.@ -0,0 +38,4 @@
return null;
}
export async function validateFetchSignature(req: IncomingMessage): Promise<SignatureValidationResult> {
This should be refactored together with the code from
packages/backend/src/queue/processors/inbox.ts
that this was copied from to work out a way that does not duplicate most of the code.I would've liked to replace the
inbox
signature code with this function, but LD signatures and the reliance on theactor
field of an activity (as well as relay logic) would make it difficult without introducing bugs, unwanted behavior, unclean code and/or more network/database requests.@ -0,0 +60,4 @@
if (keyIdLower.startsWith('acct:'))
return 'invalid';
const host = toPuny(new URL(keyIdLower).hostname);
and consequently above:
I based myself on the
inbox
code which uses the same code. I will apply the patch to my submission, but theinbox
code should probably be patched to match. (PS: I findextractDbHost
to be quite a confusing name for such a function)Do you have a suggestion for a better name (for future refactoring)?
extractHost
,extractHostname
,punyHost
, or something similar? I'm not sure; I mostly think theDb
in the name doesn't make much more sense when used in such contexts, even if that's where the function originated from.@ -0,0 +94,4 @@
// Verify the HTTP Signature
const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem);
if (httpSignatureValidated === true)
Explicitly checking for something to equal true seems unnecessary, since
httpSignature.verifySignature
has the return typeboolean
.I want to make sure the code and check condition are clear on the signature verification step, which is common practice on sensitive code. Additionally, while the typings do specify that the return type should be boolean, this is not checked at runtime, meaning that if a truthy-type is returned (for example, a non-empty string, which is common in the codebase), the check would pass. I enforce the value to be strictly the boolean value
true
instead of being truthy. This is mostly for future-proofing, for example, in case of replacement of thehttp-signature
package in the future, as the dependency itself looks fairly sound on that point.As this is uses fixups, rebase merge is preferable to not pollute Git history
Would close #29.