Skip to content

Commit

Permalink
Merge branch 'issue/TDEAL-16' of https://github.com/Lombiq/Helpful-Li…
Browse files Browse the repository at this point in the history
…braries into issue/TDEAL-16

# Conflicts:
#	Lombiq.HelpfulLibraries.AspNetCore/Security/ApplicationBuilderExtensions.cs
  • Loading branch information
sarahelsaig committed Jan 10, 2024
2 parents 6a373ce + 889cb22 commit b1a6a07
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using Lombiq.HelpfulLibraries.AspNetCore.Security;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static Lombiq.HelpfulLibraries.AspNetCore.Security.ContentSecurityPolicyDirectives;
using static Lombiq.HelpfulLibraries.AspNetCore.Security.ContentSecurityPolicyDirectives.CommonValues;

Expand Down Expand Up @@ -69,7 +72,7 @@ public static IApplicationBuilder UseContentSecurityPolicyHeader(
await provider.UpdateAsync(securityPolicies, context);
}

var policy = string.Join("; ", securityPolicies.Select((key, value) => $"{key} {value}"));
var policy = string.Join("; ", EnumerableExtensions.Select(securityPolicies, (key, value) => $"{key} {value}"));
context.Response.Headers[key] = policy;
});

Expand Down Expand Up @@ -98,4 +101,52 @@ public static IApplicationBuilder UseNosniffContentTypeOptionsHeader(this IAppli

await next();
});

/// <summary>
/// Adds a middleware that checks all <c>Set-Cookie</c> headers and replaces any with a version containing
/// <c>Secure</c> and <c>SameSite=Strict</c> modifiers if they were missing.
/// </summary>
public static IApplicationBuilder UseStrictAndSecureCookies(this IApplicationBuilder app)
{
static void UpdateIfMissing(ref string cookie, ref bool changed, string test, string append)
{
if (!cookie.ContainsOrdinalIgnoreCase(test))
{
cookie += append;
changed = true;
}
}

return app.Use((context, next) =>
{
const string setCookieHeader = "Set-Cookie";
context.Response.OnStarting(() =>
{
var setCookie = context.Response.Headers[setCookieHeader];
if (!setCookie.Any()) return Task.CompletedTask;

var newCookies = new List<string>(capacity: setCookie.Count);
var changed = false;

foreach (var cookie in setCookie.WhereNot(string.IsNullOrWhiteSpace))
{
var newCookie = cookie;

UpdateIfMissing(ref newCookie, ref changed, "SameSite", "; SameSite=Strict");
UpdateIfMissing(ref newCookie, ref changed, "Secure", "; Secure");

newCookies.Add(newCookie);
}

if (changed)
{
context.Response.Headers[setCookieHeader] = new StringValues(newCookies.ToArray());
}

return Task.CompletedTask;
});

return next();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public static OrchardCoreBuilder ConfigureSecurityDefaults(

app
.UseContentSecurityPolicyHeader(allowInlineScript, allowInlineStyle)
.UseNosniffContentTypeOptionsHeader();
.UseNosniffContentTypeOptionsHeader()
.UseStrictAndSecureCookies();
},
order: 99); // Makes this service load fairly late. This should make the setup detection more accurate.
return builder
Expand Down

0 comments on commit b1a6a07

Please sign in to comment.