Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 20 additions & 0 deletions src/Joonasw.AspNetCore.SecurityHeaders/Csp/Builder/CspBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,26 @@ public class CspBuilder
/// </summary>
public CspScriptsBuilder AllowScripts { get; } = new CspScriptsBuilder();
/// <summary>
/// Set up rules for JavaScript attributes.
/// </summary>
public CspScriptAttributesBuilder AllowScriptAttributes { get; } = new CspScriptAttributesBuilder();
/// <summary>
/// Set up rules for JavaScript elements.
/// </summary>
public CspScriptElementsBuilder AllowScriptElements { get; } = new CspScriptElementsBuilder();
/// <summary>
/// Set up rules for CSS.
/// </summary>
public CspStylesBuilder AllowStyles { get; } = new CspStylesBuilder();
/// <summary>
/// Set up rules for CSS attributes.
/// </summary>
public CspStyleAttributesBuilder AllowStyleAttributes { get; } = new CspStyleAttributesBuilder();
/// <summary>
/// Set up rules for CSS elements.
/// </summary>
public CspStyleElementsBuilder AllowStyleElements { get; } = new CspStyleElementsBuilder();
/// <summary>
/// Set up default rules for resources for which no rules exist.
/// </summary>
public CspDefaultBuilder ByDefaultAllow { get; } = new CspDefaultBuilder();
Expand Down Expand Up @@ -129,7 +145,11 @@ public void SetBlockAllMixedContent()
public CspOptions BuildCspOptions()
{
_options.Script = AllowScripts.BuildOptions();
_options.ScriptAttribute = AllowScriptAttributes.BuildOptions();
_options.ScriptElement = AllowScriptElements.BuildOptions();
_options.Style = AllowStyles.BuildOptions();
_options.StyleAttribute = AllowStyleAttributes.BuildOptions();
_options.StyleElement = AllowStyleElements.BuildOptions();
#pragma warning disable CS0618 // Type or member is obsolete
_options.Child = AllowChildren.BuildOptions();
#pragma warning restore CS0618 // Type or member is obsolete
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to JavaScript attributes.
/// </summary>
public class CspScriptAttributesBuilder : CspScriptsBuilderBase<CspScriptSrcAttributeOptions>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to JavaScript elements.
/// </summary>
public class CspScriptElementsBuilder : CspScriptsBuilderBase<CspScriptSrcElementOptions>
{
}
}
Original file line number Diff line number Diff line change
@@ -1,141 +1,12 @@
using System;
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to JavaScript.
/// </summary>
public class CspScriptsBuilder
public class CspScriptsBuilder : CspScriptsBuilderBase<CspScriptSrcOptions>
{
private readonly CspScriptSrcOptions _options = new CspScriptSrcOptions();

/// <summary>
/// Block all JavaScript.
/// </summary>
public void FromNowhere()
{
_options.AllowNone = true;
}

/// <summary>
/// Allow JavaScript from current domain.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder FromSelf()
{
_options.AllowSelf = true;
return this;
}

/// <summary>
/// Allow JavaScript from the given
/// <paramref name="uri"/>.
/// </summary>
/// <param name="uri">The URI to allow.</param>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder From(string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
if (uri.Length == 0) throw new ArgumentException("Uri can't be empty", nameof(uri));

_options.AllowedSources.Add(uri);
return this;
}

/// <summary>
/// Allow JavaScript with the given
/// <paramref name="hash"/>.
/// </summary>
/// <param name="hash">The hash to allow.</param>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder WithHash(string hash)
{
if (hash == null) throw new ArgumentNullException(nameof(hash));
if (hash.Length == 0) throw new ArgumentException("Hash can't be empty", nameof(hash));

_options.AllowedHashes.Add(hash);
return this;
}

/// <summary>
/// Allow inline scripts.
/// If you have an XSS vulnerability, this will allow them to execute.
/// Cannot be enabled together with AddNonce.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder AllowUnsafeInline()
{
_options.AllowUnsafeInline = true;
return this;
}

/// <summary>
/// Allow usage of eval(). Do not enable unless you really
/// need it.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder AllowUnsafeEval()
{
_options.AllowUnsafeEval = true;
return this;
}

/// <summary>
/// Generates a random nonce for each request and
/// adds it to the CSP header. Allows inline scripts that
/// have the nonce attribute set to the random value on
/// the script element.
/// Note that you must call AddCsp() on the service collection
/// in ConfigureServices() to add the necessary dependencies.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder AddNonce()
{
_options.AddNonce = true;
return this;
}

/// <summary>
/// Allow JavaScript from anywhere, except
/// data:, blob:, and filesystem: schemes.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder FromAnywhere()
{
_options.AllowAny = true;
return this;
}

/// <summary>
/// Allow JavaScript only over secure connections.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder OnlyOverHttps()
{
_options.AllowOnlyHttps = true;
return this;
}

/// <summary>
/// Allow scripts that have been loaded with
/// a trusted hash/nonce to load additional
/// scripts.
/// This enabled a &quot;strict&quot; mode
/// for scripts, requiring a hash or nonce
/// on all of them.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilder WithStrictDynamic()
{
_options.StrictDynamic = true;
return this;
}

public CspScriptSrcOptions BuildOptions()
{
return _options;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System;
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to JavaScript.
/// </summary>
public abstract class CspScriptsBuilderBase<TOptions>
where TOptions : CspScriptSrcOptionsBase, new()
{
private readonly TOptions _options = new TOptions();

/// <summary>
/// Block all JavaScript.
/// </summary>
public void FromNowhere()
{
_options.AllowNone = true;
}

/// <summary>
/// Allow JavaScript from current domain.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> FromSelf()
{
_options.AllowSelf = true;
return this;
}

/// <summary>
/// Allow JavaScript from the given
/// <paramref name="uri"/>.
/// </summary>
/// <param name="uri">The URI to allow.</param>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> From(string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
if (uri.Length == 0) throw new ArgumentException("Uri can't be empty", nameof(uri));

_options.AllowedSources.Add(uri);
return this;
}

/// <summary>
/// Allow JavaScript with the given
/// <paramref name="hash"/>.
/// </summary>
/// <param name="hash">The hash to allow.</param>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> WithHash(string hash)
{
if (hash == null) throw new ArgumentNullException(nameof(hash));
if (hash.Length == 0) throw new ArgumentException("Hash can't be empty", nameof(hash));

_options.AllowedHashes.Add(hash);
return this;
}

/// <summary>
/// Allow inline scripts.
/// If you have an XSS vulnerability, this will allow them to execute.
/// Cannot be enabled together with AddNonce.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> AllowUnsafeInline()
{
_options.AllowUnsafeInline = true;
return this;
}

/// <summary>
/// Allow usage of eval(). Do not enable unless you really
/// need it.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> AllowUnsafeEval()
{
_options.AllowUnsafeEval = true;
return this;
}

/// <summary>
/// Generates a random nonce for each request and
/// adds it to the CSP header. Allows inline scripts that
/// have the nonce attribute set to the random value on
/// the script element.
/// Note that you must call AddCsp() on the service collection
/// in ConfigureServices() to add the necessary dependencies.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> AddNonce()
{
_options.AddNonce = true;
return this;
}

/// <summary>
/// Allow JavaScript from anywhere, except
/// data:, blob:, and filesystem: schemes.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> FromAnywhere()
{
_options.AllowAny = true;
return this;
}

/// <summary>
/// Allow JavaScript only over secure connections.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> OnlyOverHttps()
{
_options.AllowOnlyHttps = true;
return this;
}

/// <summary>
/// Allow scripts that have been loaded with
/// a trusted hash/nonce to load additional
/// scripts.
/// This enabled a &quot;strict&quot; mode
/// for scripts, requiring a hash or nonce
/// on all of them.
/// </summary>
/// <returns>The builder for call chaining</returns>
public CspScriptsBuilderBase<TOptions> WithStrictDynamic()
{
_options.StrictDynamic = true;
return this;
}

public TOptions BuildOptions()
{
return _options;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to CSS attributes.
/// </summary>
public class CspStyleAttributesBuilder : CspStylesBuilderBase<CspStyleSrcAttributeOptions>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Joonasw.AspNetCore.SecurityHeaders.Csp.Options;

namespace Joonasw.AspNetCore.SecurityHeaders.Csp.Builder
{
/// <summary>
/// Builder for Content Security Policy
/// rules related to CSS elements.
/// </summary>
public class CspStyleElementsBuilder : CspStylesBuilderBase<CspStyleSrcElementOptions>
{
}
}
Loading