Skip to content

Commit 784e09e

Browse files
AndyButlandNuklon
andauthored
Use a regex to filter our invalid culture codes rather than relying on the culture being installed on the operating system (#19821)
* Use a regex to filter our invalid culture codes rather than relying on the culture being installed on the operating system. * Update to more restrictive regex Co-authored-by: Nuklon <[email protected]> --------- Co-authored-by: Nuklon <[email protected]>
1 parent 214f3fb commit 784e09e

File tree

2 files changed

+53
-11
lines changed

2 files changed

+53
-11
lines changed

src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -178,26 +178,31 @@ public ActionResult Frame(int id, string culture)
178178
return RedirectPermanent($"../../{id}{query}");
179179
}
180180

181-
private static bool ValidateProvidedCulture(string culture)
181+
/// <summary>
182+
/// Validates the provided culture code.
183+
/// </summary>
184+
/// <remarks>
185+
/// Marked as internal to expose for unit tests.
186+
/// </remarks>
187+
internal static bool ValidateProvidedCulture(string culture)
182188
{
183189
if (string.IsNullOrEmpty(culture))
184190
{
185191
return true;
186192
}
187193

188-
// We can be confident the backoffice will have provided a valid culture in linking to the
189-
// preview, so we don't need to check that the culture matches an Umbraco language.
190-
// We are only concerned here with protecting against XSS attacks from a fiddled preview
191-
// URL, so we can just confirm we have a valid culture.
192-
try
193-
{
194-
CultureInfo.GetCultureInfo(culture, true);
195-
return true;
196-
}
197-
catch (CultureNotFoundException)
194+
// Culture codes are expected to match this pattern.
195+
if (CultureCodeRegex().IsMatch(culture) is false)
198196
{
199197
return false;
200198
}
199+
200+
// We can be confident the backoffice will have provided a valid culture in linking to the
201+
// preview, so we don't need to check that the culture matches an Umbraco language (or is even a
202+
// valid culture code).
203+
// We are only concerned here with protecting against XSS attacks from a fiddled preview
204+
// URL, so we can proceed if the the regex is matched.
205+
return true;
201206
}
202207

203208
public ActionResult? EnterPreview(int id)
@@ -261,4 +266,7 @@ public ActionResult End(string? redir = null)
261266

262267
[GeneratedRegex("^\\/(?<id>\\d*)(\\?culture=(?<culture>[\\w-]*))?$")]
263268
private static partial Regex DefaultPreviewRedirectRegex();
269+
270+
[GeneratedRegex(@"^[a-z]{2,3}[-0-9a-z]*$", RegexOptions.IgnoreCase)]
271+
private static partial Regex CultureCodeRegex();
264272
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Umbraco.
2+
// See LICENSE for more details.
3+
4+
using System.Globalization;
5+
using NUnit.Framework;
6+
using Umbraco.Cms.Web.BackOffice.Controllers;
7+
8+
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers;
9+
10+
[TestFixture]
11+
public class PreviewControllerTests
12+
{
13+
[TestCase("en-US", true)] // A framework culture.
14+
[TestCase("en-JP", true)] // A valid culture string, but not one that's in the framework.
15+
[TestCase("a!", false)] // Not a valid culture string.
16+
[TestCase("<script>alert(123)</script>", false)]
17+
public void ValidateProvidedCulture_Validates_Culture(string culture, bool expectValid)
18+
{
19+
var result = PreviewController.ValidateProvidedCulture(culture);
20+
Assert.AreEqual(expectValid, result);
21+
}
22+
23+
[Test]
24+
public void ValidateProvidedCulture_Validates_Culture_For_All_Framework_Cultures()
25+
{
26+
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
27+
foreach (var culture in cultures)
28+
{
29+
Assert.IsTrue(PreviewController.ValidateProvidedCulture(culture.Name), $"{culture.Name} is not considered a valid culture.");
30+
Assert.IsTrue(PreviewController.ValidateProvidedCulture(culture.Name.ToUpperInvariant()), $"{culture.Name.ToUpperInvariant()} is not considered a valid culture.");
31+
Assert.IsTrue(PreviewController.ValidateProvidedCulture(culture.Name.ToLowerInvariant()), $"{culture.Name.ToLowerInvariant()} is not considered a valid culture.");
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)