From 56f36807ff18a6303752f1bb3ad079a712777017 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 14 Apr 2026 20:24:12 +0200 Subject: [PATCH] Security fixes. --- .../Backup/BackupOptions.cs | 13 +++++++++++++ .../Backup/TempFolderBackupArchiveLocation.cs | 6 +++++- .../Squidex/Areas/Api/Config/AssetFileResolver.cs | 2 +- backend/src/Squidex/Config/Domain/AssetServices.cs | 4 ++++ .../src/Squidex/Config/Domain/BackupsServices.cs | 7 ++++--- .../Squidex/Config/Domain/InfrastructureServices.cs | 4 +++- backend/src/Squidex/appsettings.json | 5 +++++ 7 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Backup/BackupOptions.cs diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupOptions.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupOptions.cs new file mode 100644 index 000000000..5e8ebe1f1 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/BackupOptions.cs @@ -0,0 +1,13 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Entities.Backup; + +public sealed class BackupOptions +{ + public bool AllowRestoreFromLocalFiles { get; set; } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs b/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs index 6eb3f88cb..17f0ed625 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Backup/TempFolderBackupArchiveLocation.cs @@ -12,7 +12,11 @@ using Squidex.Infrastructure.Json; namespace Squidex.Domain.Apps.Entities.Backup; [ExcludeFromCodeCoverage] -public sealed class TempFolderBackupArchiveLocation(IJsonSerializer serializer, IHttpClientFactory httpClientFactory) : IBackupArchiveLocation +public sealed class TempFolderBackupArchiveLocation( + IJsonSerializer serializer, + IOptions options, + IHttpClientFactory httpClientFactory) + : IBackupArchiveLocation { public async Task OpenReaderAsync(Uri url, DomainId id, CancellationToken ct) diff --git a/backend/src/Squidex/Areas/Api/Config/AssetFileResolver.cs b/backend/src/Squidex/Areas/Api/Config/AssetFileResolver.cs index a26df01cf..a7f15bdd5 100644 --- a/backend/src/Squidex/Areas/Api/Config/AssetFileResolver.cs +++ b/backend/src/Squidex/Areas/Api/Config/AssetFileResolver.cs @@ -85,7 +85,7 @@ public class AssetFileResolver(IAssetUsageTracker assetUsage, IUsageGate usageGa try { - using var httpClient = httpClientFactory.CreateClient(); + using var httpClient = httpClientFactory.CreateClient("Assets"); using var httpResponse = await httpClient.GetAsync(fileUrl, ct); var length = httpResponse.Content.Headers.ContentLength; diff --git a/backend/src/Squidex/Config/Domain/AssetServices.cs b/backend/src/Squidex/Config/Domain/AssetServices.cs index d5ebca676..ff47df2da 100644 --- a/backend/src/Squidex/Config/Domain/AssetServices.cs +++ b/backend/src/Squidex/Config/Domain/AssetServices.cs @@ -12,6 +12,7 @@ using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.Search; using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Http; namespace Squidex.Config.Domain; @@ -34,6 +35,9 @@ public static class AssetServices .As(); } + services.AddHttpClient("Assets") + .EnableSsrfProtection(); + services.AddSingletonAs() .AsSelf(); diff --git a/backend/src/Squidex/Config/Domain/BackupsServices.cs b/backend/src/Squidex/Config/Domain/BackupsServices.cs index c1c39448b..d052d3a10 100644 --- a/backend/src/Squidex/Config/Domain/BackupsServices.cs +++ b/backend/src/Squidex/Config/Domain/BackupsServices.cs @@ -12,15 +12,16 @@ using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Rules; using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Flows; -using Squidex.Infrastructure.Reflection; namespace Squidex.Config.Domain; public static class BackupsServices { - public static void AddSquidexBackups(this IServiceCollection services) + public static void AddSquidexBackups(this IServiceCollection services, IConfiguration config) { + services.Configure(config, + "backups"); + services.AddHttpClient("Backup", options => { options.Timeout = TimeSpan.FromHours(1); diff --git a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs index 5475e56af..90b0a4c0d 100644 --- a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs +++ b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs @@ -21,6 +21,7 @@ using Squidex.Domain.Apps.Entities.Contents.Counter; using Squidex.Domain.Apps.Entities.Tags; using Squidex.Infrastructure; using Squidex.Infrastructure.Diagnostics; +using Squidex.Infrastructure.Http; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.UsageTracking; @@ -45,7 +46,8 @@ public static class InfrastructureServices services.Configure(config, "diagnostics"); - services.AddHttpClient("Jint"); + services.AddHttpClient("Jint") + .EnableSsrfProtection(); services.AddReplicatedCache(); services.AddAsyncLocalCache(); diff --git a/backend/src/Squidex/appsettings.json b/backend/src/Squidex/appsettings.json index a089b8f37..7400e8b64 100644 --- a/backend/src/Squidex/appsettings.json +++ b/backend/src/Squidex/appsettings.json @@ -101,6 +101,11 @@ "allowAutoRedirect": false }, + "backups": { + // Enables to download backups from the local file system. + "allowRestoreFromLocalFiles": false + }, + "caching": { // Set to true, to use strong etags. "strongETag": false,