Enhance: Add configuration option to disable all external redirects when responding to an ActivityPub lookup (config.disallowExternalApRedirect)
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
This commit is contained in:
parent
cc641ecbc5
commit
c31466e463
8 changed files with 62 additions and 2 deletions
|
@ -251,5 +251,10 @@ allowedPrivateNetworks: [
|
|||
'127.0.0.1/32'
|
||||
]
|
||||
|
||||
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||
#disallowExternalApRedirect: true
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
|
|
@ -266,6 +266,11 @@ signToActivityPubGet: true
|
|||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
||||
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||
#disallowExternalApRedirect: true
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
|
|
|
@ -365,6 +365,11 @@ signToActivityPubGet: true
|
|||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
||||
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||
#disallowExternalApRedirect: true
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 2025.2.0-yumechinokuni.2
|
||||
|
||||
- Enhance: 成り済まし対策として、ActivityPub照会された時にリモートのリダイレクトを拒否できるように (config.disallowExternalApRedirect)
|
||||
|
||||
## 2025.2.0-yumechinokuni.1
|
||||
|
||||
- Security: Revert miskey-dev/misskey#14897
|
||||
|
|
2
locales/index.d.ts
vendored
2
locales/index.d.ts
vendored
|
@ -10884,7 +10884,7 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"title": string;
|
||||
/**
|
||||
* このサーバーと通信することはできましたが、得られたデータが不正なものでした。
|
||||
* このサーバーと通信することはできましたが、得られたデータが不正なものでした。第三者サーバーのURIを使った場合はオリジナルのURIを使用して照会し直してください。
|
||||
*/
|
||||
"description": string;
|
||||
};
|
||||
|
|
|
@ -2908,7 +2908,7 @@ _remoteLookupErrors:
|
|||
description: "このサーバーとの通信に失敗しました。相手サーバーがダウンしている可能性があります。また、不正なURIや存在しないURIを入力していないか確認してください。"
|
||||
_responseInvalid:
|
||||
title: "レスポンスが不正です"
|
||||
description: "このサーバーと通信することはできましたが、得られたデータが不正なものでした。"
|
||||
description: "このサーバーと通信することはできましたが、得られたデータが不正なものでした。第三者サーバーのURIを使った場合はオリジナルのURIを使用して照会し直してください。"
|
||||
_responseInvalidIdHostNotMatch:
|
||||
description: "入力されたURIのドメインと最終的に得られたURIのドメインとが異なります。第三者のサーバーを介してリモートのコンテンツを照会している場合は、発信元のサーバーで取得できるURIを使用して照会し直してください。"
|
||||
_noSuchObject:
|
||||
|
|
|
@ -92,6 +92,7 @@ type Source = {
|
|||
proxyBypassHosts?: string[];
|
||||
|
||||
allowedPrivateNetworks?: string[];
|
||||
disallowExternalApRedirect?: boolean;
|
||||
|
||||
maxFileSize?: number;
|
||||
|
||||
|
@ -169,6 +170,7 @@ export type Config = {
|
|||
proxySmtp: string | undefined;
|
||||
proxyBypassHosts: string[] | undefined;
|
||||
allowedPrivateNetworks: string[] | undefined;
|
||||
disallowExternalApRedirect: boolean;
|
||||
maxFileSize: number;
|
||||
clusterLimit: number | undefined;
|
||||
id: string;
|
||||
|
@ -332,6 +334,7 @@ export function loadConfig(): Config {
|
|||
proxySmtp: config.proxySmtp,
|
||||
proxyBypassHosts: config.proxyBypassHosts,
|
||||
allowedPrivateNetworks: config.allowedPrivateNetworks,
|
||||
disallowExternalApRedirect: config.disallowExternalApRedirect ?? false,
|
||||
maxFileSize: config.maxFileSize ?? 262144000,
|
||||
clusterLimit: config.clusterLimit,
|
||||
outgoingAddress: config.outgoingAddress,
|
||||
|
|
|
@ -320,6 +320,44 @@ export class ServerService implements OnApplicationShutdown {
|
|||
serve: false,
|
||||
});
|
||||
|
||||
// if the requester looks like to be performing an ActivityPub object lookup, reject all external redirects
|
||||
//
|
||||
// this will break lookup that involve copying a URL from a third-party server, like trying to lookup http://charlie.example.com/@alice@alice.com
|
||||
// but I think we should not allow this regardless, open redirect is not a good pattern especially in machine-to-machine communication.
|
||||
//
|
||||
// this is not required by standard but protect us from peers that did not validate final URL.
|
||||
if (this.config.disallowExternalApRedirect) {
|
||||
const maybeApLookupRegex = /application\/activity\+json|application\/ld\+json.+activitystreams/i;
|
||||
fastify.addHook('onSend', (request, reply, _, done) => {
|
||||
const location = reply.getHeader('location');
|
||||
if (reply.statusCode < 300 || reply.statusCode >= 400 || typeof location !== 'string') {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!maybeApLookupRegex.test(request.headers.accept ?? '')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
const effectiveLocation = process.env.NODE_ENV === 'production' ? location : location.replace(/^http:\/\//, 'https://');
|
||||
if (effectiveLocation.startsWith(`https://${this.config.host}`)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
reply.status(406);
|
||||
reply.removeHeader('location');
|
||||
reply.header('content-type', 'text/plain; charset=utf-8');
|
||||
reply.header('link', `<${encodeURI(effectiveLocation)}>; rel="canonical"`);
|
||||
done(null, [
|
||||
"Refusing to relay remote ActivityPub object lookup.",
|
||||
"",
|
||||
`Please remove 'application/activity+json' and 'application/ld+json' from the Accept header or fetch using the authoritative URL at ${effectiveLocation}.`,
|
||||
].join('\n'));
|
||||
});
|
||||
}
|
||||
|
||||
fastify.register(this.apiServerService.createServer, { prefix: '/api' });
|
||||
fastify.register(this.openApiServerService.createServer);
|
||||
fastify.register(this.fileServerService.createServer);
|
||||
|
|
Loading…
Add table
Reference in a new issue