forked from FoundKeyGang/FoundKey
server: forbid activitypub requests on unexpected routes
ActivityPub requests on routes which do not support activitypub are now replying with HTTP status code 406 "Not Acceptable". ActivityPub clients are required by the W3C TR to set the `Accept` header. If this accept header is detected on an unexpected route, the whole request will be aborted with the status code above. This is an additional measure for clients who might not be aware of having to check the content-type header of the reply. Ref: https://github.com/w3c/activitypub/issues/432 Changelog: Security
This commit is contained in:
parent
e366116ac1
commit
624157f03e
4 changed files with 18 additions and 0 deletions
|
@ -55,6 +55,18 @@ function isActivityPubReq(ctx: Router.RouterContext): boolean {
|
|||
return typeof accepted === 'string' && !accepted.match(/html/);
|
||||
}
|
||||
|
||||
export function denyActivityPub() {
|
||||
return async (ctx, next) => {
|
||||
if (!isActivityPubReq(ctx)) return await next();
|
||||
|
||||
// Clients are required to set the `Accept` header to an Activitypub content type.
|
||||
// If such a content type negotiation header is received on an unexpected route,
|
||||
// something seems to be fishy and we should not respond with content. A user
|
||||
// might have e.g. uploaded a malicious file that looks like an activity.
|
||||
ctx.status = 406;
|
||||
};
|
||||
}
|
||||
|
||||
export function setResponseType(ctx: Router.RouterContext): void {
|
||||
const accept = ctx.accepts(ACTIVITY_JSON, LD_JSON);
|
||||
if (accept === LD_JSON) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import cors from '@koa/cors';
|
|||
|
||||
import { Instances, AccessTokens, Users } from '@/models/index.js';
|
||||
import config from '@/config/index.js';
|
||||
import { denyActivityPub } from '@/server/activitypub.js';
|
||||
import { endpoints } from './endpoints.js';
|
||||
import { handler } from './api-handler.js';
|
||||
import signup from './private/signup.js';
|
||||
|
@ -24,6 +25,7 @@ const app = new Koa();
|
|||
app.use(cors({
|
||||
origin: '*',
|
||||
}));
|
||||
app.use(denyActivityPub());
|
||||
|
||||
// No caching
|
||||
app.use(async (ctx, next) => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { dirname } from 'node:path';
|
|||
import Koa from 'koa';
|
||||
import cors from '@koa/cors';
|
||||
import Router from '@koa/router';
|
||||
import { denyActivityPub } from '@/server/activitypub.js';
|
||||
import { sendDriveFile } from './send-drive-file.js';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
|
@ -16,6 +17,7 @@ const _dirname = dirname(_filename);
|
|||
// Init app
|
||||
const app = new Koa();
|
||||
app.use(cors());
|
||||
app.use(denyActivityPub());
|
||||
app.use(async (ctx, next) => {
|
||||
ctx.set('Content-Security-Policy', "default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'");
|
||||
await next();
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
import Koa from 'koa';
|
||||
import cors from '@koa/cors';
|
||||
import Router from '@koa/router';
|
||||
import { denyActivityPub } from '@/server/activitypub.js';
|
||||
import { proxyMedia } from './proxy-media.js';
|
||||
|
||||
// Init app
|
||||
const app = new Koa();
|
||||
app.use(cors());
|
||||
app.use(denyActivityPub());
|
||||
app.use(async (ctx, next) => {
|
||||
ctx.set('Content-Security-Policy', "default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'");
|
||||
await next();
|
||||
|
|
Loading…
Reference in a new issue