Skip to content

Commit

Permalink
DNN-10601: preventing handling external URLs in image handler.
Browse files Browse the repository at this point in the history
  • Loading branch information
galatrash committed Jan 5, 2018
1 parent 9afe07c commit d3953db
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 7 deletions.
23 changes: 21 additions & 2 deletions DNN Platform/Library/Services/GeneratedImage/DnnImageHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Drawing;
Expand Down Expand Up @@ -233,11 +234,14 @@ public override ImageInfo GenerateImage(NameValueCollection parameters)
}
else if (!string.IsNullOrEmpty(parameters["Url"]))
{
if (!parameters["Url"].StartsWith("http"))
var url = parameters["Url"];
// allow only site resources when using the url parameter
if (!url.StartsWith("http") || !UriBelongsToSite(new Uri(url)))
{
return GetEmptyImageInfo();
}
imgUrl = parameters["Url"];

imgUrl = url;
}

if (string.IsNullOrEmpty(parameters["format"]))
Expand Down Expand Up @@ -555,5 +559,20 @@ private static ImageFormat GetImageFormat(string extension)
return ImageFormat.Png;
}
}

// checks whether the uri belongs to any of the site-wide aliases
private static bool UriBelongsToSite(Uri uri)
{
IEnumerable<string> hostAliases =
from PortalAliasInfo alias in PortalAliasController.Instance.GetPortalAliases().Values
select alias.HTTPAlias.ToLowerInvariant();

// if URI, for example, = "http(s)://myDomain:80/DNNDev/myPage?var=name" , then the two strings will be
// uriNoScheme1 = "mydomain/dnndev/mypage" -- lower case
// uriNoScheme2 = "mydomain:80/dnndev/mypage" -- lower case
var uriNoScheme1 = (uri.DnsSafeHost + uri.LocalPath).ToLowerInvariant();
var uriNoScheme2 = (uri.Authority + uri.LocalPath).ToLowerInvariant();
return hostAliases.Any(alias => uriNoScheme1.StartsWith(alias) || uriNoScheme2.StartsWith(alias));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ public ImageResizeTransform() {
/// <param name="image">Input image</param>
/// <returns>Image result after image transformation</returns>
public override Image ProcessImage(Image image)
{
{
if (image == null)
return null;

if (MaxWidth > 0)
{
Width = image.Width > MaxWidth ? MaxWidth : image.Width;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ private void RenderImage(Image image, Stream outStream)
Param = { [0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, ImageCompression) }
};
var ici = GetEncoderInfo(GetImageMimeType(ContentType));
image.Save(outStream, ici, eps);
image?.Save(outStream, ici, eps);
}
}
finally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<Compile Include="Helpers\FolderHelper.cs" />
<Compile Include="Helpers\HostSettingsHelper.cs" />
<Compile Include="Helpers\MockComponentHelper.cs" />
<Compile Include="Helpers\PortalAliasHelper.cs" />
<Compile Include="Helpers\PortalInfoHelper.cs" />
<Compile Include="Helpers\PortalSettingsHelper.cs" />
<Compile Include="Helpers\StoredProcedureStatsHelper.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// DotNetNuke® - http://www.dnnsoftware.com
// Copyright (c) 2002-2018, DNN Corp.
// All Rights Reserved

using System.Collections.Generic;
using System.Linq;
using DotNetNuke.Entities.Portals;

namespace DNN.Integration.Test.Framework.Helpers
{
public class PortalAliasHelper
{
public static PortalAliasInfo GetPrimaryPortalAlias(int portalId = 0)
{
return DatabaseHelper.ExecuteStoredProcedure<PortalAliasInfo>("GetPortalAliases").First(p => p.PortalID == portalId && p.IsPrimary);
}

public static IEnumerable<PortalAliasInfo> GetPortalAliaes(int portalId = 0)
{
return DatabaseHelper.ExecuteStoredProcedure<PortalAliasInfo>("GetPortalAliases").Where(p => p.PortalID == portalId);
}

public static IEnumerable<PortalAliasInfo> GetAllPortalAliaes()
{
return DatabaseHelper.ExecuteStoredProcedure<PortalAliasInfo>("GetPortalAliases");
}

public static void AddPortalAlias(PortalAliasInfo portal)
{
DatabaseHelper.ExecuteStoredProcedure("AddPortalAlias",
portal.PortalID,
portal.HTTPAlias,
portal.CultureCode,
portal.Skin,
portal.BrowserType,
portal.IsPrimary,
-1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
<Compile Include="PersonaBar\Content\Pages\AddPageTests.cs" />
<Compile Include="PersonaBar\Content\Pages\PageUrlsTests.cs" />
<Compile Include="PersonaBar\Manage\Users\UsersFiltersTests.cs" />
<Compile Include="Tests\Library\ImageHandlerTests.cs" />
<Compile Include="Tests\Portals\PortalInfoTests.cs" />
<Compile Include="Tests\Portals\PortalSettingsTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// DotNetNuke® - http://www.dnnsoftware.com
// Copyright (c) 2002-2018, DNN Corp.
// All Rights Reserved

using System.Linq;
using DNN.Integration.Test.Framework;
using DNN.Integration.Test.Framework.Helpers;
using DotNetNuke.Entities.Portals;
using NUnit.Framework;

namespace DotNetNuke.Tests.Integration.Tests.Library
{
[TestFixture]
public class ImageHandlerTests : IntegrationTestBase
{
// we assume this GIF image exists in all DNN sites and it shouldn't be PNG
private const string HandlerPath = "/DnnImageHandler.ashx?mode=file&w=1&url={0}/images/1x1.GIF";

[Test]
public void Using_Image_Handler_For_Foreign_Site_ShouldFail()
{
var session = WebApiTestHelper.GetAnnonymousConnector();
var relativeUrl = string.Format(HandlerPath, "https://google.com");

var response = session.GetContent(relativeUrl).Content.ReadAsStringAsync().Result;
Assert.IsTrue(response.StartsWith("�PNG\r\n"), $"Content = {response}");
}

[Test]
public void Using_Image_Handler_For_Main_Alias_ShouldPass()
{
var session = WebApiTestHelper.GetAnnonymousConnector();
var relativeUrl = string.Format(HandlerPath, AppConfigHelper.SiteUrl);

var response = session.GetContent(relativeUrl).Content.ReadAsStringAsync().Result;
Assert.IsTrue(response.StartsWith("GIF89a"), $"Content = {response}");
}

[Test]
public void Using_Image_Handler_From_All_Alias_ShouldPass()
{
PortalAliasInfo pai;
var aliases = PortalAliasHelper.GetPortalAliaes().ToList();
if (aliases.Count == 1)
{
var primary = aliases.First();
pai = new PortalAliasInfo
{
PortalID = primary.PortalID,
HTTPAlias = "my-" + primary.HTTPAlias,
CultureCode = primary.CultureCode,
Skin = primary.Skin,
BrowserType = primary.BrowserType,
IsPrimary = false,

};
}
else
{
pai = aliases.First(a => a.PortalAliasID > 1);
}

var session = WebApiTestHelper.GetAnnonymousConnector();
aliases = PortalAliasHelper.GetPortalAliaes().ToList();
foreach (var alias in aliases)
{
var relativeUrl = string.Format(HandlerPath, AppConfigHelper.SiteUrl);
var absoluteUrl = $"http://{alias.HTTPAlias}{relativeUrl}";
LogText("Getting image from " + absoluteUrl);

var response = session.GetContent(absoluteUrl).Content.ReadAsStringAsync().Result;
Assert.IsTrue(response.StartsWith("GIF89a"), $"Url: {absoluteUrl} / Content = {response}");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
// DotNetNuke® - http://www.dnnsoftware.com
// Copyright (c) 2002-2018, DNN Corp.
// All Rights Reserved

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using DNN.Integration.Test.Framework;
using DNN.Integration.Test.Framework.Helpers;
using NUnit.Framework;
Expand Down

0 comments on commit d3953db

Please sign in to comment.