fix(server): "forkbomb" DOS mitigation (#9247)
* Add recursion limit to resolver * Use shared resolver in featured and question * Changelog * Changelog fix * Update CHANGELOG.md Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> * Add host to recursion limit error message Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
This commit is contained in:
parent
5decad9cf1
commit
66513b9893
|
@ -25,6 +25,7 @@ You should also include the user name that made the change.
|
|||
- Server: 引用内の文章がnyaizeされてしまう問題を修正 @kabo2468
|
||||
- Server: Bug fix for Pinned Users lookup on instance @squidicuzz
|
||||
- Client: インスタンスティッカーのfaviconを読み込む際に偽サイト警告が出ることがあるのを修正 @syuilo
|
||||
- Server: Mitigate AP reference chain DoS vector @skehmatics
|
||||
|
||||
## 12.119.0 (2022/09/10)
|
||||
|
||||
|
|
|
@ -731,7 +731,7 @@ export class ApInboxService {
|
|||
await this.apPersonService.updatePerson(actor.uri!, resolver, object);
|
||||
return 'ok: Person updated';
|
||||
} else if (getApType(object) === 'Question') {
|
||||
await this.apQuestionService.updateQuestion(object).catch(err => console.error(err));
|
||||
await this.apQuestionService.updateQuestion(object, resolver).catch(err => console.error(err));
|
||||
return 'ok: Question updated';
|
||||
} else {
|
||||
return `skip: Unknown type: ${getApType(object)}`;
|
||||
|
|
|
@ -76,6 +76,7 @@ export class Resolver {
|
|||
private httpRequestService: HttpRequestService,
|
||||
private apRendererService: ApRendererService,
|
||||
private apDbResolverService: ApDbResolverService,
|
||||
private recursionLimit = 100
|
||||
) {
|
||||
this.history = new Set();
|
||||
}
|
||||
|
@ -116,6 +117,10 @@ export class Resolver {
|
|||
throw new Error('cannot resolve already resolved one');
|
||||
}
|
||||
|
||||
if (this.history.size > this.recursionLimit) {
|
||||
throw new Error(`hit recursion limit: ${this.utilityService.extractDbHost(value)}`);
|
||||
}
|
||||
|
||||
this.history.add(value);
|
||||
|
||||
const host = this.utilityService.extractDbHost(value);
|
||||
|
|
|
@ -390,7 +390,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
});
|
||||
//#endregion
|
||||
|
||||
await this.updateFeatured(user!.id).catch(err => this.logger.error(err));
|
||||
await this.updateFeatured(user!.id, resolver).catch(err => this.logger.error(err));
|
||||
|
||||
return user!;
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
followerSharedInbox: person.sharedInbox ?? (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
});
|
||||
|
||||
await this.updateFeatured(exist.id).catch(err => this.logger.error(err));
|
||||
await this.updateFeatured(exist.id, resolver).catch(err => this.logger.error(err));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -551,14 +551,14 @@ export class ApPersonService implements OnModuleInit {
|
|||
return { fields, services };
|
||||
}
|
||||
|
||||
public async updateFeatured(userId: User['id']) {
|
||||
public async updateFeatured(userId: User['id'], resolver?: Resolver) {
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: userId });
|
||||
if (!this.userEntityService.isRemoteUser(user)) return;
|
||||
if (!user.featured) return;
|
||||
|
||||
this.logger.info(`Updating the featured: ${user.uri}`);
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||
|
||||
// Resolve to (Ordered)Collection Object
|
||||
const collection = await resolver.resolveCollection(user.featured);
|
||||
|
|
|
@ -65,7 +65,7 @@ export class ApQuestionService {
|
|||
* @param uri URI of AP Question object
|
||||
* @returns true if updated
|
||||
*/
|
||||
public async updateQuestion(value: any) {
|
||||
public async updateQuestion(value: any, resolver?: Resolver) {
|
||||
const uri = typeof value === 'string' ? value : value.id;
|
||||
|
||||
// URIがこのサーバーを指しているならスキップ
|
||||
|
@ -80,7 +80,7 @@ export class ApQuestionService {
|
|||
//#endregion
|
||||
|
||||
// resolve new Question object
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||
const question = await resolver.resolve(value) as IQuestion;
|
||||
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||
|
||||
|
|
Loading…
Reference in a new issue