Browse Source

Added script nonce

pull/16496/head
Salih 4 years ago
parent
commit
7265f73abf
  1. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs
  2. 1
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreConsts.cs
  3. 25
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs
  4. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersOptions.cs

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs

@ -49,6 +49,9 @@ public class AbpTagHelperScriptService : AbpTagHelperResourceService
var deferText = (defer || Options.DeferScriptsByDefault || Options.DeferScripts.Any(x => file.StartsWith(x, StringComparison.OrdinalIgnoreCase))) var deferText = (defer || Options.DeferScriptsByDefault || Options.DeferScripts.Any(x => file.StartsWith(x, StringComparison.OrdinalIgnoreCase)))
? "defer" ? "defer"
: string.Empty; : string.Empty;
output.Content.AppendHtml($"<script {deferText} src=\"{viewContext.GetUrlHelper().Content(file.EnsureStartsWith('~'))}\"></script>{Environment.NewLine}"); var nonceText = (viewContext.HttpContext.Items.TryGetValue(AbpAspNetCoreConsts.ScriptNonceKey, out var nonce) && nonce is string nonceString && !string.IsNullOrEmpty(nonceString))
? $"nonce=\"{nonceString}\""
: string.Empty;
output.Content.AppendHtml($"<script {deferText} {nonceText} src=\"{viewContext.GetUrlHelper().Content(file.EnsureStartsWith('~'))}\"></script>{Environment.NewLine}");
} }
} }

1
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreConsts.cs

@ -4,4 +4,5 @@ public static class AbpAspNetCoreConsts
{ {
public const string DefaultApiPrefix = "api"; public const string DefaultApiPrefix = "api";
public const string DefaultIntegrationServiceApiPrefix = "integration-api"; public const string DefaultIntegrationServiceApiPrefix = "integration-api";
public const string ScriptNonceKey = "ScriptNonce";
} }

25
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -27,13 +28,31 @@ public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency
/*The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>. SAMEORIGIN makes it being displayed in a frame on the same origin as the page itself. The spec leaves it up to browser vendors to decide whether this option applies to the top level, the parent, or the whole chain*/ /*The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>. SAMEORIGIN makes it being displayed in a frame on the same origin as the page itself. The spec leaves it up to browser vendors to decide whether this option applies to the top level, the parent, or the whole chain*/
AddHeader(context, "X-Frame-Options", "SAMEORIGIN"); AddHeader(context, "X-Frame-Options", "SAMEORIGIN");
var contentSecurityPolicyValueDictionary = Options.Value.ContentSecurityPolicyValueDictionary.ToDictionary(x=>x.Key, x=>x.Value);
if (Options.Value.UseContentSecurityPolicyHeader) if (Options.Value.UseContentSecurityPolicyHeader)
{ {
if (Options.Value.UseContentSecurityPolicyNonce)
{
if (!context.Items.ContainsKey(AbpAspNetCoreConsts.ScriptNonceKey))
{
var randomValue = Guid.NewGuid().ToString("N");
context.Items.Add(AbpAspNetCoreConsts.ScriptNonceKey, randomValue);
if (contentSecurityPolicyValueDictionary.TryGetValue("script-src", out var scriptSrc))
{
contentSecurityPolicyValueDictionary["script-src"] = scriptSrc.Append($"'nonce-{randomValue}'");
}
else
{
contentSecurityPolicyValueDictionary.Add("script-src", new[] { $"'nonce-{randomValue}'" });
}
}
}
AddHeader(context, "Content-Security-Policy", AddHeader(context, "Content-Security-Policy",
Options.Value.ContentSecurityPolicyValue.IsNullOrEmpty() Options.Value.ContentSecurityPolicyValueDictionary.Any()
? "object-src 'none'; form-action 'self'; frame-ancestors 'none'" ? string.Join("; ", contentSecurityPolicyValueDictionary.Select(x => $"{x.Key} {string.Join(" ", x.Value)}"))
: Options.Value.ContentSecurityPolicyValue); : "object-src 'none'; form-action 'self'; frame-ancestors 'none'");
} }
foreach (var (key, value) in Options.Value.Headers) foreach (var (key, value) in Options.Value.Headers)

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersOptions.cs

@ -5,13 +5,16 @@ namespace Volo.Abp.AspNetCore.Security;
public class AbpSecurityHeadersOptions public class AbpSecurityHeadersOptions
{ {
public bool UseContentSecurityPolicyHeader { get; set; } public bool UseContentSecurityPolicyHeader { get; set; }
public bool UseContentSecurityPolicyNonce { get; set; }
public string ContentSecurityPolicyValue { get; set; } public Dictionary<string,IEnumerable<string>> ContentSecurityPolicyValueDictionary { get; }
public Dictionary<string, string> Headers { get; } public Dictionary<string, string> Headers { get; }
public AbpSecurityHeadersOptions() public AbpSecurityHeadersOptions()
{ {
Headers = new Dictionary<string, string>(); Headers = new Dictionary<string, string>();
ContentSecurityPolicyValueDictionary = new Dictionary<string, IEnumerable<string>>();
} }
} }

Loading…
Cancel
Save