Merge pull request #13900 from umbraco/v10/bugfix/12200

Add allowlist of media hosts.
This commit is contained in:
Bjarke Berg
2023-03-02 14:34:05 +01:00
committed by GitHub
2 changed files with 52 additions and 4 deletions

View File

@@ -262,4 +262,9 @@ public class ContentSettings
/// </summary>
[DefaultValue(StaticDisallowedUploadFiles)]
public string[] DisallowedUploadedFileExtensions { get; set; } = StaticDisallowedUploadFiles.Split(',');
/// <summary>
/// Gets or sets the allowed external host for media. If empty only relative paths are allowed.
/// </summary>
public string[] AllowedMediaHosts { get; set; } = Array.Empty<string>();
}

View File

@@ -1,10 +1,14 @@
using System.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Media;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Web.Common.Attributes;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Web.BackOffice.Controllers;
@@ -17,13 +21,31 @@ public class ImagesController : UmbracoAuthorizedApiController
{
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly MediaFileManager _mediaFileManager;
private ContentSettings _contentSettings;
[Obsolete("Use non obsolete-constructor. Scheduled for removal in Umbraco 13.")]
public ImagesController(
MediaFileManager mediaFileManager,
IImageUrlGenerator imageUrlGenerator)
: this(mediaFileManager,
imageUrlGenerator,
StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<ContentSettings>>())
{
}
[ActivatorUtilitiesConstructor]
public ImagesController(
MediaFileManager mediaFileManager,
IImageUrlGenerator imageUrlGenerator,
IOptionsMonitor<ContentSettings> contentSettingsMonitor)
{
_mediaFileManager = mediaFileManager;
_imageUrlGenerator = imageUrlGenerator;
_contentSettings = contentSettingsMonitor.CurrentValue;
contentSettingsMonitor.OnChange(x => _contentSettings = x);
}
/// <summary>
@@ -58,7 +80,7 @@ public class ImagesController : UmbracoAuthorizedApiController
var ext = Path.GetExtension(encodedImagePath);
// check if imagePath is local to prevent open redirect
if (!Uri.IsWellFormedUriString(encodedImagePath, UriKind.Relative))
if (!IsAllowed(encodedImagePath))
{
return Unauthorized();
}
@@ -90,12 +112,33 @@ public class ImagesController : UmbracoAuthorizedApiController
ImageCropMode = ImageCropMode.Max,
CacheBusterValue = rnd
});
if (Url.IsLocalUrl(imageUrl))
if (imageUrl is not null)
{
return new LocalRedirectResult(imageUrl, false);
return new RedirectResult(imageUrl, false);
}
return Unauthorized();
return NotFound();
}
private bool IsAllowed(string encodedImagePath)
{
if(Uri.IsWellFormedUriString(encodedImagePath, UriKind.Relative))
{
return true;
}
var builder = new UriBuilder(encodedImagePath);
foreach (var allowedMediaHost in _contentSettings.AllowedMediaHosts)
{
if (string.Equals(builder.Host, allowedMediaHost, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
/// <summary>