From 90ffd25d96bd41edcd4fe7f25b37813898206ab8 Mon Sep 17 00:00:00 2001 From: Jason Elkin Date: Tue, 11 Oct 2022 01:41:50 +0100 Subject: [PATCH] Swap HSTS healthcheck status on localhost (cherry picked from commit 6cb53fd703ac7a66922c2d19c5118a3263c522af) --- .../EmbeddedResources/Lang/en.xml | 6 +++ .../EmbeddedResources/Lang/en_us.xml | 6 +++ .../HealthChecks/Checks/Security/HstsCheck.cs | 54 ++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml index c3d2ab8bb4..b04155137b 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml @@ -2349,6 +2349,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Strict-Transport-Security, also known as the HSTS-header, was found.]]> Strict-Transport-Security was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found. This header should not be present on localhost.]]> + + + Strict-Transport-Security was not found. This header should not be present on localhost.]]> + X-XSS-Protection was found.]]> X-XSS-Protection was not found.]]> diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml index 6ddedc7797..4a025ed25c 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml @@ -2451,6 +2451,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Strict-Transport-Security, also known as the HSTS-header, was found.]]> Strict-Transport-Security was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found. This header should not be present on localhost.]]> + + + Strict-Transport-Security was not found. This header should not be present on localhost.]]> + X-XSS-Protection was found.]]> X-XSS-Protection was not found.]]> diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs index 229999472e..0637404045 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs @@ -3,6 +3,7 @@ using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; namespace Umbraco.Cms.Core.HealthChecks.Checks.Security; @@ -16,6 +17,11 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security; Group = "Security")] public class HstsCheck : BaseHttpHeaderCheck { + private const string LocalizationPrefix = "hSTS"; + + private readonly IHostingEnvironment _hostingEnvironment; + private readonly ILocalizedTextService _textService; + /// /// Initializes a new instance of the class. /// @@ -27,10 +33,56 @@ public class HstsCheck : BaseHttpHeaderCheck /// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites. /// public HstsCheck(IHostingEnvironment hostingEnvironment, ILocalizedTextService textService) - : base(hostingEnvironment, textService, "Strict-Transport-Security", "hSTS", true) + : base(hostingEnvironment, textService, "Strict-Transport-Security", LocalizationPrefix, true) { + _hostingEnvironment = hostingEnvironment; + _textService = textService; } /// protected override string ReadMoreLink => Constants.HealthChecks.DocumentationLinks.Security.HstsCheck; + + /// + public override async Task> GetStatus() => + new HealthCheckStatus[] { await CheckForHeader() }; + + /// + /// The health check task. + /// + /// A with the result type reversed on localhost. + protected new async Task CheckForHeader() + { + HealthCheckStatus checkHeaderResult = await base.CheckForHeader(); + + var isLocalhost = _hostingEnvironment.ApplicationMainUrl?.Host.ToLowerInvariant() == "localhost"; + + // when not on localhost, the header should exist. + if (!isLocalhost) + { + return checkHeaderResult; + } + + string message; + StatusResultType statusResultType; + + // on localhost the header should not exist, so invert the status. + if (checkHeaderResult.ResultType == StatusResultType.Success) + { + statusResultType = StatusResultType.Error; + + message = _textService.Localize("healthcheck", $"{LocalizationPrefix}CheckHeaderFoundOnLocalhost"); + } + else + { + statusResultType = StatusResultType.Success; + + message = _textService.Localize("healthcheck", $"{LocalizationPrefix}CheckHeaderNotFoundOnLocalhost"); + } + + return new HealthCheckStatus(message) + { + ResultType = statusResultType, + ReadMoreLink = ReadMoreLink, + }; + } }