Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding in changes for the nonce service #33

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/Joonasw.AspNetCore.SecurityHeaders/Csp/CspNonceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ namespace Joonasw.AspNetCore.SecurityHeaders.Csp
public class CspNonceService : ICspNonceService
{
private readonly string _nonce;
private static char base64PadCharacter = '=';
private static string doubleBase64PadCharacter = "==";
private static char base64Character62 = '+';
juunas11 marked this conversation as resolved.
Show resolved Hide resolved
private static char base64Character63 = '/';
private static char base64UrlCharacter62 = '-';
private static char _base64UrlCharacter63 = '_';

public CspNonceService(int nonceByteAmount = 32)
{
Expand All @@ -15,7 +21,15 @@ public CspNonceService(int nonceByteAmount = 32)
rng.GetBytes(nonceBytes);
}

_nonce = Convert.ToBase64String(nonceBytes);
var s = Convert.ToBase64String(nonceBytes);
// a base64String can have elements that aren't URL friendly. In testing chrome appeared to ignore nonces that weren't URL friendly (or the tag helper did).
// the replacement code comes from Microsoft.IdentityModel.Tokens.Base64UrlEncoder
s = s.Split(base64PadCharacter)[0]; // Remove any trailing padding
s = s.Replace(base64Character62, base64UrlCharacter62); // 62nd char of encoding
s = s.Replace(base64Character63, _base64UrlCharacter63); // 63rd char of encoding

_nonce = s;

}

public string GetNonce()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
{
// The nonce service is created per request, so we
// get the same nonce here as the CSP header
output.Attributes.Add("nonce", _nonceService.GetNonce());
// when doing this, the nonce wasn't reliably being injected (that might have been due to the nonce have non url friendly chars).
//output.Attributes.Add("nonce", _nonceService.GetNonce());
// this injected the nonce all the time.
var attribute = new TagHelperAttribute("nonce", _nonceService.GetNonce(), HtmlAttributeValueStyle.DoubleQuotes);
output.Attributes.SetAttribute(attribute);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

namespace Joonasw.AspNetCore.SecurityHeaders.Tests
{
public class CspScriptsBuilderTests
using Csp;

public class CspScriptsBuilderTests
{
[Fact]
public void FromNowhere_SetsAllowNoneToTrue()
Expand All @@ -30,6 +32,24 @@ public void FromSelf_SetsAllowSelfToTrue()
Assert.True(options.AllowSelf);
}

[Fact]
public void FromSelf_WithNonce_HasValue()
{
var nonceService = new CspNonceService(32);
var nonce = nonceService.GetNonce();

var builder = new CspBuilder();
builder.AllowScripts.FromSelf().AddNonce();

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

Assert.DoesNotContain("+", nonce);
Assert.DoesNotContain("/", nonce);
Assert.DoesNotContain("=", nonce);

Assert.Equal($"script-src 'self' 'nonce-{nonce}'", headerValue);
}

[Fact]
public void From_AddsUrlToAllowedSources()
{
Expand Down