diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 4ca06c7..4d86f10 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 8.0.x + dotnet-version: 6.0.x - name: Install dotnet-format tool run: dotnet tool install -g dotnet-format @@ -43,7 +43,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3 with: - dotnet-version: '8.0.x' + dotnet-version: '6.0.x' - name: Install dependencies run: dotnet restore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8bf8459..8e0cc88 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3 with: - dotnet-version: '8.0.x' + dotnet-version: '6.0.x' - name: Install dependencies run: dotnet restore diff --git a/OwaspHeaders.Core.Example/Controllers/HomeController.cs b/OwaspHeaders.Core.Example/Controllers/HomeController.cs index aa028a3..d940fb6 100644 --- a/OwaspHeaders.Core.Example/Controllers/HomeController.cs +++ b/OwaspHeaders.Core.Example/Controllers/HomeController.cs @@ -1,22 +1,21 @@ -using Microsoft.AspNetCore.Mvc; - -namespace OwaspHeaders.Core.Example.Controllers -{ - [ApiController] - [Route("/")] - public class HomeController : ControllerBase - { - private readonly ILogger _logger; - - public HomeController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "/")] - public IEnumerable Get() - { - return HttpContext.Response.Headers.Select(h => h.ToString()).ToArray(); - } - } -} +using Microsoft.AspNetCore.Mvc; + +namespace OwaspHeaders.Core.Example.Controllers; + +[ApiController] +[Route("/")] +public class HomeController : ControllerBase +{ + private readonly ILogger _logger; + + public HomeController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "/")] + public IEnumerable Get() + { + return HttpContext.Response.Headers.Select(h => h.ToString()).ToArray(); + } +} diff --git a/OwaspHeaders.Core.Example/Helpers/RealisticContentSecurityPolicyGenerators.cs b/OwaspHeaders.Core.Example/Helpers/RealisticContentSecurityPolicyGenerators.cs new file mode 100644 index 0000000..c863dc1 --- /dev/null +++ b/OwaspHeaders.Core.Example/Helpers/RealisticContentSecurityPolicyGenerators.cs @@ -0,0 +1,160 @@ +using OwaspHeaders.Core.Enums; +using OwaspHeaders.Core.Extensions; +using OwaspHeaders.Core.Models; + +namespace OwaspHeaders.Core.Example.Helpers; + +/// +/// This class is useful for testing the Secure Headers middleware with a set of realistic +/// settings. It is currently (as of June 7th, 2023) not being used but I would prefer that +/// it sticks around as it would be very useful to use in the future. +/// This flies against standard Software Engineering practises. But this particular csproj +/// is only provided for developers to test the OwaspHeaders.Core project whilst they are +/// developing it (i.e. without having to push to GitHub, wait for a build, wait for a PR, +/// wait for a release, wait for NuGet to index, and wait for it to download). +/// +public static class RealisticContentSecurityPolicyGenerators +{ + /// + /// Represents an instance of the with + /// the Content-Security Policy from the OWASP homepage. + /// + /// + /// The instance of hte 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 😛) + /// + /// + /// An instance of the with headers which + /// represent the Content-Security Policy taken from the OWASP website homepage on May 15th, 2023 + /// + public static SecureHeadersMiddlewareConfiguration GenerateOwaspHomePageCsp() => + SecureHeadersMiddlewareExtensions.BuildDefaultConfiguration() + .UseContentSecurityPolicy() + .SetCspUris( + new List + { + 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 + { + 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 + { + 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 + { + 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 + { + 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 + { + new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" }, + new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "fonts.gstatic.com" } + }, CspUriType.Font) + .SetCspUris( + new List + { + new() { CommandType = CspCommandType.Directive, DirectiveOrUri = "self" }, + new() { CommandType = CspCommandType.Uri, DirectiveOrUri = "https://pay.google.com" } + }, CspUriType.Manifest) + .SetCspUris( + new List + { + 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); +} diff --git a/OwaspHeaders.Core.Example/OwaspHeaders.Core.Example.csproj b/OwaspHeaders.Core.Example/OwaspHeaders.Core.Example.csproj index f09c1ae..110993a 100644 --- a/OwaspHeaders.Core.Example/OwaspHeaders.Core.Example.csproj +++ b/OwaspHeaders.Core.Example/OwaspHeaders.Core.Example.csproj @@ -1,8 +1,7 @@ - OwaspHeaders.Core.Example - net6.0;net7.0;net8.0 + net6.0 enable enable @@ -11,8 +10,6 @@ - - diff --git a/OwaspHeaders.Core.Example/Program.cs b/OwaspHeaders.Core.Example/Program.cs index f484384..4ed2a19 100644 --- a/OwaspHeaders.Core.Example/Program.cs +++ b/OwaspHeaders.Core.Example/Program.cs @@ -1,29 +1,29 @@ -using OwaspHeaders.Core.Extensions; - -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. - -builder.Services.AddControllers(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} - -app.UseHttpsRedirection(); - -app.UseAuthorization(); - -app.UseSecureHeadersMiddleware(); - -app.MapControllers(); - -app.Run(); +using OwaspHeaders.Core.Extensions; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.UseSecureHeadersMiddleware(); + +app.MapControllers(); + +app.Run(); diff --git a/OwaspHeaders.Core.Example/Properties/launchSettings.json b/OwaspHeaders.Core.Example/Properties/launchSettings.json index ddd5fcd..a8bac65 100644 --- a/OwaspHeaders.Core.Example/Properties/launchSettings.json +++ b/OwaspHeaders.Core.Example/Properties/launchSettings.json @@ -1,41 +1,31 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:4604", - "sslPort": 44302 - } - }, - "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:5281", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "https://localhost:7189;http://localhost:5281", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "swagger", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:24885", + "sslPort": 44362 + } + }, + "profiles": { + "example": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7001;http://localhost:5265", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/OwaspHeaders.Core.Example/appsettings.Development.json b/OwaspHeaders.Core.Example/appsettings.Development.json index 0c208ae..ff66ba6 100644 --- a/OwaspHeaders.Core.Example/appsettings.Development.json +++ b/OwaspHeaders.Core.Example/appsettings.Development.json @@ -1,8 +1,8 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/OwaspHeaders.Core.Example/appsettings.json b/OwaspHeaders.Core.Example/appsettings.json index 10f68b8..4d56694 100644 --- a/OwaspHeaders.Core.Example/appsettings.json +++ b/OwaspHeaders.Core.Example/appsettings.json @@ -1,9 +1,9 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -} +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/OwaspHeaders.Core.Tests/OwaspHeaders.Core.Tests.csproj b/OwaspHeaders.Core.Tests/OwaspHeaders.Core.Tests.csproj index 090259f..5a33d19 100644 --- a/OwaspHeaders.Core.Tests/OwaspHeaders.Core.Tests.csproj +++ b/OwaspHeaders.Core.Tests/OwaspHeaders.Core.Tests.csproj @@ -4,7 +4,7 @@ 8.0.0 Jamie Taylor OwaspHeaders.Core.Tests - net6.0;net7.0;net8.0 + net6.0;net7.0 diff --git a/src/OwaspHeaders.Core.csproj b/src/OwaspHeaders.Core.csproj index dc9a05a..d8e80ba 100644 --- a/src/OwaspHeaders.Core.csproj +++ b/src/OwaspHeaders.Core.csproj @@ -4,7 +4,7 @@ 8.0.0 Jamie Taylor OwaspHeaders.Core - net6.0;net7.0;net8.0 + net6.0;net7.0 OwaspHeaders.Core 2.0.0 LICENSE.txt