From a72f30e79822f0d383ec24deac743e15f86a3aa8 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 14 Oct 2024 14:48:08 -0700 Subject: [PATCH 1/5] Localization Cookie Static Conditional HttpOnly=True --- Oqtane.Server/Components/App.razor | 43 +++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 35d713223..e359c85fd 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -604,19 +604,38 @@ private void SetLocalizationCookie(string culture) { - var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions + if (_renderMode == RenderModes.Static) { - Expires = DateTimeOffset.UtcNow.AddYears(1), - SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute - Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = false // cookie is updated using JS Interop in Interactive render mode - }; - - Context.Response.Cookies.Append( - CookieRequestCultureProvider.DefaultCookieName, - CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), - cookieOptions - ); + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions + { + Expires = DateTimeOffset.UtcNow.AddYears(1), + SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute + Secure = true, // Ensure the cookie is only sent over HTTPS + HttpOnly = true // Optional: Helps mitigate XSS attacks + }; + + Context.Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), + cookieOptions + ); + } + else + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions + { + Expires = DateTimeOffset.UtcNow.AddYears(1), + SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute + Secure = true, // Ensure the cookie is only sent over HTTPS + HttpOnly = false // cookie is updated using JS Interop + }; + + Context.Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), + cookieOptions + ); + } } private async Task> GetPageResources(Alias alias, Site site, Page page, List modules, int moduleid, string action) From 167c3f68c6cb2f83f37f4233b72166f55bc6115f Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 14 Oct 2024 15:29:47 -0700 Subject: [PATCH 2/5] Update culture cookie HttpOnly true/false based on render mode --- Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor b/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor index 819c8d724..8d250960c 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor +++ b/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor @@ -61,7 +61,7 @@ Expires = DateTimeOffset.UtcNow.AddYears(365), SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = false // cookie is updated using JS Interop in Interactive render mode + HttpOnly = PageState.RenderMode == RenderModes.Static // sets the cookie HttpOnly=true only if the rendermode is not updated using JS Interop in Interactive render mode }); } From d9c43c6388104685cae4d19d50086ace6e0a3fb8 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 14 Oct 2024 15:33:01 -0700 Subject: [PATCH 3/5] refactor HttpOnly = True/False Culture Cookie Render Mode --- Oqtane.Server/Components/App.razor | 43 +++++++++--------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index e359c85fd..ca510b5d2 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -604,38 +604,19 @@ private void SetLocalizationCookie(string culture) { - if (_renderMode == RenderModes.Static) + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions { - var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions - { - Expires = DateTimeOffset.UtcNow.AddYears(1), - SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute - Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = true // Optional: Helps mitigate XSS attacks - }; - - Context.Response.Cookies.Append( - CookieRequestCultureProvider.DefaultCookieName, - CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), - cookieOptions - ); - } - else - { - var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions - { - Expires = DateTimeOffset.UtcNow.AddYears(1), - SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute - Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = false // cookie is updated using JS Interop - }; - - Context.Response.Cookies.Append( - CookieRequestCultureProvider.DefaultCookieName, - CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), - cookieOptions - ); - } + Expires = DateTimeOffset.UtcNow.AddYears(1), + SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute + Secure = true, // Ensure the cookie is only sent over HTTPS + HttpOnly = _renderMode == RenderModes.Static // Set HttpOnly based on render mode + }; + + Context.Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), + cookieOptions + ); } private async Task> GetPageResources(Alias alias, Site site, Page page, List modules, int moduleid, string action) From d1c35e027b653b5f26d7a6fe1dd4e9a28c2b4f4d Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 14 Oct 2024 15:45:33 -0700 Subject: [PATCH 4/5] Update HttpOnly Culture Cookie Comment For Clarity --- Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor b/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor index 8d250960c..23ee7a091 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor +++ b/Oqtane.Client/Themes/Controls/Theme/LanguageSwitcher.razor @@ -61,7 +61,9 @@ Expires = DateTimeOffset.UtcNow.AddYears(365), SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = PageState.RenderMode == RenderModes.Static // sets the cookie HttpOnly=true only if the rendermode is not updated using JS Interop in Interactive render mode + HttpOnly = PageState.RenderMode == RenderModes.Static // Sets the cookie with HttpOnly=true only if the render mode is Static. + // In Interactive mode, cookies are updated using JavaScript Interop, + // which requires HttpOnly to be false. }); } From 3a40159fd7e71f0a0bb993f19a97a557be0a3766 Mon Sep 17 00:00:00 2001 From: Cody Date: Mon, 14 Oct 2024 15:47:49 -0700 Subject: [PATCH 5/5] Update comment for HttpOnly culture cookie handling logic Refactor cookie handling to set HttpOnly based on render mode - Set HttpOnly=true for Static render mode and HttpOnly=false for Interactive mode. --- Oqtane.Server/Components/App.razor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index ca510b5d2..2d9c85196 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -609,7 +609,9 @@ Expires = DateTimeOffset.UtcNow.AddYears(1), SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute Secure = true, // Ensure the cookie is only sent over HTTPS - HttpOnly = _renderMode == RenderModes.Static // Set HttpOnly based on render mode + HttpOnly = _renderMode == RenderModes.Static // Sets the cookie with HttpOnly=true only if the render mode is Static. + // In Interactive mode, cookies are updated using JavaScript Interop, + // which requires HttpOnly to be false. }; Context.Response.Cookies.Append(