From 44e880807971a9b5f7f3df85a0ee5a47a0cb973a Mon Sep 17 00:00:00 2001 From: Matt Brailsford Date: Thu, 3 Mar 2022 10:42:14 +0000 Subject: [PATCH] Check form and querystring when validating `ufprt` in `ValidateUmbracoFormRouteStringAttribute` (#11957) * Check form and querystring when validating ufprt Checks to see if the request has form data before validating the `ufprt` parameter, and if it doesn't assumes it must be on the querystring * Create GetUfprt extension method * Use GetUfprt extension * Update UmbracoRouteValueTransformer to use GetUfrpt() * Added missing using statement * Check for StringValues.Empty --- .../Extensions/HttpRequestExtensions.cs | 21 +++++++++++++++++++ ...ValidateUmbracoFormRouteStringAttribute.cs | 2 +- .../Routing/UmbracoRouteValueTransformer.cs | 18 ++++++++-------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs index 2aeb2555eb..7d9ce136ef 100644 --- a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Routing; @@ -136,5 +137,25 @@ namespace Umbraco.Extensions return new Uri(routingSettings.UmbracoApplicationUrl); } + + /// + /// Gets the Umbraco `ufprt` encrypted string from the current request + /// + /// The current request + /// The extracted `ufprt` token. + public static string GetUfprt(this HttpRequest request) + { + if (request.HasFormContentType && request.Form.TryGetValue("ufprt", out StringValues formVal) && formVal != StringValues.Empty) + { + return formVal.ToString(); + } + + if (request.Query.TryGetValue("ufprt", out StringValues queryVal) && queryVal != StringValues.Empty) + { + return queryVal.ToString(); + } + + return null; + } } } diff --git a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs index ed86d7c783..0c51edd4e1 100644 --- a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs @@ -42,7 +42,7 @@ namespace Umbraco.Cms.Web.Common.Filters { if (context == null) throw new ArgumentNullException(nameof(context)); - var ufprt = context.HttpContext.Request.Form["ufprt"]; + var ufprt = context.HttpContext.Request.GetUfprt(); if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) { diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 9106c3ed09..60384de752 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -201,23 +201,23 @@ namespace Umbraco.Cms.Web.Website.Routing throw new ArgumentNullException(nameof(httpContext)); } - // if it is a POST/GET then a value must be in the request - if ((!httpContext.Request.HasFormContentType || !httpContext.Request.Form.TryGetValue("ufprt", out StringValues encodedVal)) - && !httpContext.Request.Query.TryGetValue("ufprt", out encodedVal)) + // if it is a POST/GET then a `ufprt` value must be in the request + var ufprt = httpContext.Request.GetUfprt(); + if (string.IsNullOrWhiteSpace(ufprt)) { return null; } if (!EncryptionHelper.DecryptAndValidateEncryptedRouteString( _dataProtectionProvider, - encodedVal, - out IDictionary decodedParts)) + ufprt, + out IDictionary decodedUfprt)) { return null; } // Get all route values that are not the default ones and add them separately so they eventually get to action parameters - foreach (KeyValuePair item in decodedParts.Where(x => ReservedAdditionalKeys.AllKeys.Contains(x.Key) == false)) + foreach (KeyValuePair item in decodedUfprt.Where(x => ReservedAdditionalKeys.AllKeys.Contains(x.Key) == false)) { values[item.Key] = item.Value; } @@ -225,9 +225,9 @@ namespace Umbraco.Cms.Web.Website.Routing // return the proxy info without the surface id... could be a local controller. return new PostedDataProxyInfo { - ControllerName = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Controller).Value), - ActionName = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Action).Value), - Area = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Area).Value), + ControllerName = WebUtility.UrlDecode(decodedUfprt.First(x => x.Key == ReservedAdditionalKeys.Controller).Value), + ActionName = WebUtility.UrlDecode(decodedUfprt.First(x => x.Key == ReservedAdditionalKeys.Action).Value), + Area = WebUtility.UrlDecode(decodedUfprt.First(x => x.Key == ReservedAdditionalKeys.Area).Value), }; }