BREAKING: activitypub: validate fetch signatures #399
Loading…
Add table
Add a link
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),
allowUnsignedFetchescan be set totruein 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
exported since it isn't used in other modules/files.The
exportis 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 unifiedhandleSignatureshouldn'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.tsthat this was copied from to work out a way that does not duplicate most of the code.I would've liked to replace the
inboxsignature code with this function, but LD signatures and the reliance on theactorfield 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
inboxcode which uses the same code. I will apply the patch to my submission, but theinboxcode should probably be patched to match. (PS: I findextractDbHostto 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 theDbin 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 Signatureconst httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem);if (httpSignatureValidated === true)Explicitly checking for something to equal true seems unnecessary, since
httpSignature.verifySignaturehas 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
trueinstead of being truthy. This is mostly for future-proofing, for example, in case of replacement of thehttp-signaturepackage 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.