Skip to content

Commit

Permalink
Merge pull request #85 from jamie-taylor-rjj/feature/perf-tests-1
Browse files Browse the repository at this point in the history
Fixed bug where spaces where appearing between CSP directives and URIs.
  • Loading branch information
GaProgMan authored May 15, 2023
2 parents 0db058d + 4f9f0bf commit 19474cc
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 89 deletions.
151 changes: 151 additions & 0 deletions example/Helpers/RealisticContentSecurityPolicyGenerators.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
using OwaspHeaders.Core.Enums;
using OwaspHeaders.Core.Extensions;
using OwaspHeaders.Core.Models;

namespace example.Helpers;

public static class RealisticContentSecurityPolicyGenerators
{
/// <summary>
/// Represents an instance of the <see cref="SecureHeadersMiddlewareConfiguration"/> with
/// the Content-Security Policy from the OWASP homepage.
/// </summary>
/// <remarks>
/// The instance of hte <see cref="SecureHeadersMiddlewareConfiguration"/> that this method
/// returns, DOES NOT contain any other header values. The return value from this method is
/// provided as a way of testing the CSP generation code. And should NOT be used in a live
/// environment (unless you are replacing the OWASP website with ASP .NET Core 😛)
/// </remarks>
/// <returns>
/// An instance of the <see cref="SecureHeadersMiddlewareConfiguration"/> with headers which
/// represent the Content-Security Policy taken from the OWASP website homepage on May 15th, 2023
/// </returns>
public static SecureHeadersMiddlewareConfiguration GenerateOwaspHomePageCsp() =>
SecureHeadersMiddlewareExtensions.BuildDefaultConfiguration()
.UseContentSecurityPolicy()
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://api.github.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.githubusercontent.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.google-analytics.com" },
new()
{
CommandType = CspCommandType.Uri,
DirectiveOrUri = "https://owaspadmin.azurewebsites.net"
},
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twimg.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://platform.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://www.youtube.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.doubleclick.net" }
}, CspUriType.DefaultUri)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://api.github.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.githubusercontent.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.google-analytics.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://owaspadmin.azurewebsites.net" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twimg.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://platform.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://www.youtube.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.doubleclick.net" },
}, CspUriType.FrameAncestors)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.vuejs.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.stripe.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.wufoo.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.sched.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.google.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://www.youtube.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://w.soundcloud.com" },
}, CspUriType.Frame)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "unsafe-inline" },
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "unsafe-eval" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://fonts.googleapis.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://app.diagrams.net" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://cdnjs.cloudflare.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://cse.google.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.vuejs.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.stripe.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.wufoo.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.youtube.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.meetup.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.sched.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.google-analytics.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://unpkg.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://buttons.github.io" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://www.google.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.gstatic.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twimg.com" },
}, CspUriType.Script)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "unsafe-inline" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.gstatic.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://cdnjs.cloudflare.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://www.google.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://fonts.googleapis.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://platform.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twimg.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "data:" },
}, CspUriType.Style)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "fonts.gstatic.com" }
}, CspUriType.Font)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://pay.google.com" }
}, CspUriType.Manifest)
.SetCspUris(
new List<ContentSecurityPolicyElement>
{
new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.globalappsec.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "data:" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "www.w3.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://licensebuttons.net" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://img.shields.io" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://github.githubassets.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.twimg.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://platform.twitter.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.githubusercontent.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.vercel.app" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.cloudfront.net" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.coreinfrastructure.org" },
new()
{
CommandType = CspCommandType.Uri,
DirectiveOrUri = "https://*.securityknowledgeframework.org"
},
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://badges.gitter.im" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://travis-ci.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://api.travis-ci.org" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://s3.amazonaws.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://snyk.io" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://coveralls.io" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://requires.io" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://github.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.googleapis.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.google.com" },
new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://*.gstatic.com" },
}, CspUriType.Img);
}
5 changes: 3 additions & 2 deletions example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using OwaspHeaders.Core.Extensions;
using example.Helpers;
using OwaspHeaders.Core.Extensions;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -22,7 +23,7 @@

app.UseAuthorization();

app.UseSecureHeadersMiddleware(SecureHeadersMiddlewareExtensions.BuildDefaultConfiguration());
app.UseSecureHeadersMiddleware(RealisticContentSecurityPolicyGenerators.GenerateOwaspHomePageCsp());

app.MapControllers();

Expand Down
6 changes: 3 additions & 3 deletions src/Extensions/StringBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class StringBuilderExtensions
/// </summary>
/// <param name="sb"></param>
/// <returns></returns>
private static StringBuilder TrimEnd(this StringBuilder sb)
public static StringBuilder TrimEnd(this StringBuilder sb)
{
if (sb == null || sb.Length == 0) return sb;

Expand Down Expand Up @@ -52,8 +52,8 @@ public static StringBuilder BuildValuesForDirective(this StringBuilder stringBui

if (directives.Any())
{
stringBuilder.Append(string.Join(EmptySpace, directives.Select(directive => $"'{directive.DirectiveOrUri}'")));
stringBuilder.Append(EmptySpace);
stringBuilder.Append(string.Join(EmptySpace,
directives.Select(directive => $"'{directive.DirectiveOrUri}'")));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/OwaspHeaders.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>An ASP.NET Core Middleware which adds the OWASP recommended HTTP headers for enhanced security.</Description>
<VersionPrefix>6.0.5</VersionPrefix>
<VersionPrefix>6.1.0</VersionPrefix>
<Authors>Jamie Taylor</Authors>
<AssemblyName>OwaspHeaders.Core</AssemblyName>
<TargetFramework>netstandard2.0</TargetFramework>
Expand Down
2 changes: 1 addition & 1 deletion src/OwaspHeadersCore.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>OwaspHeaders.Core</id>
<version>6.0.5</version>
<version>6.1.0</version>
<authors>GaProgMan</authors>
<owners>GaProgMan</owners>
<readme>docs\README-NuGet.md</readme>
Expand Down
16 changes: 12 additions & 4 deletions src/SecureHeadersMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class SecureHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly SecureHeadersMiddlewareConfiguration _config;
private string _calculatedContentSecurityPolicy;

public SecureHeadersMiddleware(RequestDelegate next, SecureHeadersMiddlewareConfiguration config)
{
Expand Down Expand Up @@ -59,20 +60,27 @@ public async Task InvokeAsync(HttpContext httpContext)

if (_config.UseContentSecurityPolicyReportOnly)
{

if (string.IsNullOrWhiteSpace(_calculatedContentSecurityPolicy))
{
_calculatedContentSecurityPolicy = _config.ContentSecurityPolicyReportOnlyConfiguration.BuildHeaderValue();
}
httpContext.TryAddHeader(Constants.ContentSecurityPolicyReportOnlyHeaderName,
_config.ContentSecurityPolicyReportOnlyConfiguration.BuildHeaderValue());
_calculatedContentSecurityPolicy);
}
else if (_config.UseContentSecurityPolicy)
{
if (string.IsNullOrWhiteSpace(_calculatedContentSecurityPolicy))
{
_calculatedContentSecurityPolicy = _config.ContentSecurityPolicyConfiguration.BuildHeaderValue();
}
httpContext.TryAddHeader(Constants.ContentSecurityPolicyHeaderName,
_config.ContentSecurityPolicyConfiguration.BuildHeaderValue());
_calculatedContentSecurityPolicy);
}

if (_config.UseXContentSecurityPolicy)
{
httpContext.TryAddHeader(Constants.XContentSecurityPolicyHeaderName,
_config.ContentSecurityPolicyConfiguration.BuildHeaderValue());
_config.ContentSecurityPolicyConfiguration.BuildHeaderValue());
}

if (_config.UsePermittedCrossDomainPolicy)
Expand Down
74 changes: 0 additions & 74 deletions tests/RegressionTests.cs

This file was deleted.

Loading

0 comments on commit 19474cc

Please sign in to comment.