diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index 5f15c4e0d..67875b3e6 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -328,6 +328,12 @@ namespace ImageProcessor.Web.HttpModules string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty; string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString); + // Check whether the path is valid for other requests. + if (!isFileLocal && !currentService.IsValidRequest(requestPath + "?" + urlParameters)) + { + return; + } + // Create a new cache to help process and cache the request. DiskCache cache = new DiskCache(requestPath, fullPath, queryString); string cachedPath = cache.CachedPath; @@ -548,12 +554,7 @@ namespace ImageProcessor.Web.HttpModules } // Return the file based service - if (ImageHelpers.IsValidImageExtension(path)) - { - return services.FirstOrDefault(s => string.IsNullOrWhiteSpace(s.Prefix)); - } - - return null; + return services.FirstOrDefault(s => string.IsNullOrWhiteSpace(s.Prefix) && s.IsValidRequest(path)); } #endregion } diff --git a/src/ImageProcessor.Web/Services/IImageService.cs b/src/ImageProcessor.Web/Services/IImageService.cs index 3488f30cf..dfdcf0cdc 100644 --- a/src/ImageProcessor.Web/Services/IImageService.cs +++ b/src/ImageProcessor.Web/Services/IImageService.cs @@ -43,6 +43,17 @@ namespace ImageProcessor.Web.Services /// Uri[] WhiteList { get; set; } + /// + /// Gets a value indicating whether the current request passes sanitizing rules. + /// + /// + /// The image path. + /// + /// + /// True if the request is valid; otherwise, False. + /// + bool IsValidRequest(string path); + /// /// Gets the image using the given identifier. /// diff --git a/src/ImageProcessor.Web/Services/LocalFileImageService.cs b/src/ImageProcessor.Web/Services/LocalFileImageService.cs index c9726b2eb..499753753 100644 --- a/src/ImageProcessor.Web/Services/LocalFileImageService.cs +++ b/src/ImageProcessor.Web/Services/LocalFileImageService.cs @@ -16,6 +16,8 @@ namespace ImageProcessor.Web.Services using System.Threading.Tasks; using System.Web; + using ImageProcessor.Web.Helpers; + /// /// The local file image service for retrieving images from the file system. /// @@ -67,6 +69,20 @@ namespace ImageProcessor.Web.Services /// public Uri[] WhiteList { get; set; } + /// + /// Gets a value indicating whether the current request passes sanitizing rules. + /// + /// + /// The image path. + /// + /// + /// True if the request is valid; otherwise, False. + /// + public bool IsValidRequest(string path) + { + return ImageHelpers.IsValidImageExtension(path); + } + /// /// Gets the image using the given identifier. /// diff --git a/src/ImageProcessor.Web/Services/RemoteImageService.cs b/src/ImageProcessor.Web/Services/RemoteImageService.cs index acebdf5d0..010beb413 100644 --- a/src/ImageProcessor.Web/Services/RemoteImageService.cs +++ b/src/ImageProcessor.Web/Services/RemoteImageService.cs @@ -14,7 +14,6 @@ namespace ImageProcessor.Web.Services using System.Collections.Generic; using System.IO; using System.Net; - using System.Security; using System.Threading.Tasks; using ImageProcessor.Web.Helpers; @@ -84,6 +83,44 @@ namespace ImageProcessor.Web.Services /// public Uri[] WhiteList { get; set; } + /// + /// Gets a value indicating whether the current request passes sanitizing rules. + /// + /// + /// The image path. + /// + /// + /// True if the request is valid; otherwise, False. + /// + public bool IsValidRequest(string path) + { + // Check the url is from a whitelisted location. + Uri url = new Uri(path); + string upper = url.Host.ToUpperInvariant(); + + // Check for root or sub domain. + bool validUrl = false; + foreach (Uri uri in this.WhiteList) + { + if (!uri.IsAbsoluteUri) + { + Uri rebaseUri = new Uri("http://" + uri.ToString().TrimStart(new[] { '.', '/' })); + validUrl = upper.StartsWith(rebaseUri.Host.ToUpperInvariant()) || upper.EndsWith(rebaseUri.Host.ToUpperInvariant()); + } + else + { + validUrl = upper.StartsWith(uri.Host.ToUpperInvariant()) || upper.EndsWith(uri.Host.ToUpperInvariant()); + } + + if (validUrl) + { + break; + } + } + + return validUrl; + } + /// /// Gets the image using the given identifier. /// @@ -96,10 +133,6 @@ namespace ImageProcessor.Web.Services public async Task GetImage(object id) { Uri uri = new Uri(id.ToString()); - - // Check the url is from a whitelisted location. - this.CheckSafeUrlLocation(uri); - RemoteFile remoteFile = new RemoteFile(uri) { MaxDownloadSize = int.Parse(this.Settings["MaxBytes"]), @@ -132,41 +165,5 @@ namespace ImageProcessor.Web.Services return buffer; } - - /// - /// Returns a value indicating whether the current url is in a list of safe download locations. - /// - /// - /// The to check against. - /// - private void CheckSafeUrlLocation(Uri url) - { - string upper = url.Host.ToUpperInvariant(); - - // Check for root or sub domain. - bool validUrl = false; - foreach (Uri uri in this.WhiteList) - { - if (!uri.IsAbsoluteUri) - { - Uri rebaseUri = new Uri("http://" + uri.ToString().TrimStart(new[] { '.', '/' })); - validUrl = upper.StartsWith(rebaseUri.Host.ToUpperInvariant()) || upper.EndsWith(rebaseUri.Host.ToUpperInvariant()); - } - else - { - validUrl = upper.StartsWith(uri.Host.ToUpperInvariant()) || upper.EndsWith(uri.Host.ToUpperInvariant()); - } - - if (validUrl) - { - break; - } - } - - if (!validUrl) - { - throw new SecurityException("Application is not configured to allow remote file downloads from this domain."); - } - } } } diff --git a/src/TestWebsites/MVC/Web.config b/src/TestWebsites/MVC/Web.config index 9bef44eaf..eb09cc6d7 100644 --- a/src/TestWebsites/MVC/Web.config +++ b/src/TestWebsites/MVC/Web.config @@ -27,7 +27,7 @@ - +