Skip to content

Commit

Permalink
Merge pull request #43 from MrMDavidson/add-require-sri-for
Browse files Browse the repository at this point in the history
Adds support for "require-sri-for" value
  • Loading branch information
juunas11 authored Jun 21, 2019
2 parents 00b0434 + f3073fd commit 4672d84
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ public class CspBuilder
/// </summary>
public CspBaseUriBuilder AllowBaseUri { get; } = new CspBaseUriBuilder();

/// <summary>
/// Setups up rules for controlling when subresource integrity must be used
/// </summary>
public CspRequireSriBuilder RequireSri { get; } = new CspRequireSriBuilder();

public Func<CspSendingHeaderContext, Task> OnSendingHeader { get; set; } = context => Task.CompletedTask;

/// <summary>
Expand Down Expand Up @@ -144,8 +149,9 @@ public CspOptions BuildCspOptions()
_options.Worker = AllowWorkers.BuildOptions();
_options.Prefetch = AllowPrefetch.BuildOptions();
_options.BaseUri = AllowBaseUri.BuildOptions();
_options.RequireSri = RequireSri.BuildOptions();
_options.OnSendingHeader = OnSendingHeader;
return _options;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder {
public class CspRequireSriBuilder {
private readonly CspRequireSriOptions _options = new CspRequireSriOptions();

/// <summary>
/// Require subresource integrity attributes for scripts loaded on this page
/// </summary>
public CspRequireSriBuilder ForScripts()
{
_options.ForScripts = true;
return this;
}

/// <summary>
/// Require subresource integrity attributes for styles loaded on this page
/// </summary>
public CspRequireSriBuilder ForStyles()
{
_options.ForStyles = true;
return this;
}

public CspRequireSriOptions BuildOptions()
{
return _options;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Options {
public class CspRequireSriOptions {
/// <summary>
/// If <c>true</c> subresource integrity attributes will be required for scripts loaded from this page
/// </summary>
public bool ForScripts { get; set; }

/// <summary>
/// If <c>true</c> subresource integrity attributes will be required for stylesheets loaded from this page
/// </summary>
public bool ForStyles { get; set; }

/// <inheritdoc />
public override string ToString() {
if ((ForScripts == false) && (ForStyles == false))
{
return string.Empty;
}

List<string> requiredOn = new List<string>(2);
if (ForScripts == true)
{
requiredOn.Add("script");
}
if (ForStyles == true)
{
requiredOn.Add("style");
}

return $"require-sri-for {string.Join(" ", requiredOn)}";

}
}
}
12 changes: 10 additions & 2 deletions src/Joonasw.AspNetCore.SecurityHeaders/CspOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ public class CspOptions
/// can do.
/// </summary>
public CspSandboxOptions Sandbox { get; set; }

/// <summary>
/// Options for controlling what subresource integrity attributes should be required on
/// </summary>
public CspRequireSriOptions RequireSri { get; set; }

/// <summary>
/// The URL where violation reports should be sent.
/// </summary>
Expand Down Expand Up @@ -154,6 +160,7 @@ public CspOptions()
FrameAncestors = new CspFrameAncestorsOptions();
PluginTypes = new CspPluginTypesOptions();
Sandbox = new CspSandboxOptions();
RequireSri = new CspRequireSriOptions();
Frame = new CspFrameSrcOptions();
Worker = new CspWorkerSrcOptions();
Prefetch = new CspPrefetchSrcOptions();
Expand Down Expand Up @@ -192,7 +199,8 @@ public CspOptions()
Frame.ToString(nonceService),
Worker.ToString(nonceService),
Prefetch.ToString(nonceService),
BaseUri.ToString(nonceService)
BaseUri.ToString(nonceService),
RequireSri.ToString()
};
if (BlockAllMixedContent)
{
Expand All @@ -216,4 +224,4 @@ public CspOptions()
return (headerName, headerValue);
}
}
}
}
1 change: 0 additions & 1 deletion test/Joonasw.AspNetCore.SecurityHeaders.Samples/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
app.UseStaticFiles();

app.UseCsp();

// Manual configuration
//app.UseCsp(csp =>
//{
Expand Down
14 changes: 13 additions & 1 deletion test/Joonasw.AspNetCore.SecurityHeaders.Tests/CspBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Joonasw.AspNetCore.SecurityHeaders.Csp;
using Joonasw.AspNetCore.SecurityHeaders.Csp.Builder;
Expand Down Expand Up @@ -116,6 +116,18 @@ public void WithManifest_ReturnsCorrectHeader()
Assert.Equal("manifest-src https://www.google.com", headerValue);
}

[Fact]
public void RequireSriFor_ReturnsCorrectHeader()
{
var builder = new CspBuilder();

builder.RequireSri.ForScripts();

var headerValue = builder.BuildCspOptions().ToString(null).headerValue;

Assert.Equal("require-sri-for script", headerValue);
}

[Fact]
public async Task OnSendingHeader_ShouldNotSendTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,18 @@ public void ManyOptions_ResultIsCorrect()
{
"userscripts.example.com"
}
},
RequireSri = new CspRequireSriOptions()
{
ForScripts = true,
ForStyles = true
}
};

var (headerName, headerValue) = options.ToString(null);

Assert.Equal("Content-Security-Policy", headerName);
Assert.Equal("default-src 'self';script-src userscripts.example.com;img-src *;media-src media1.com media2.com", headerValue);
Assert.Equal("default-src 'self';script-src userscripts.example.com;img-src *;media-src media1.com media2.com;require-sri-for script style", headerValue);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Builder;
using Xunit;

namespace Joonasw.AspNetCore.SecurityHeaders.Tests
{
public class CspRequireSriBuilderTests
{
[Fact]
public void NoOptions_DoesNotGenerateHeader()
{
var builder = new CspRequireSriBuilder();

var options = builder.BuildOptions();

Assert.True(string.IsNullOrWhiteSpace(options.ToString()));
}

[Fact]
public void RequireScript_GeneratesHeader()
{
var builder = new CspRequireSriBuilder();
builder.ForScripts();

var options = builder.BuildOptions();

Assert.Equal("require-sri-for script", options.ToString());
}

[Fact]
public void RequireStyle_GeneratesHeader()
{
var builder = new CspRequireSriBuilder();
builder.ForStyles();

var options = builder.BuildOptions();

Assert.Equal("require-sri-for style", options.ToString());
}

[Fact]
public void RequireScriptAndStyle_GeneratesHeader()
{
var builder = new CspRequireSriBuilder();
builder.ForScripts();
builder.ForStyles();

var options = builder.BuildOptions();

Assert.Equal("require-sri-for script style", options.ToString());
}
}
}

0 comments on commit 4672d84

Please sign in to comment.