QuokkaDev.SecurityHeaders 4.0.0

dotnet add package QuokkaDev.SecurityHeaders --version 4.0.0
NuGet\Install-Package QuokkaDev.SecurityHeaders -Version 4.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="QuokkaDev.SecurityHeaders" Version="4.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add QuokkaDev.SecurityHeaders --version 4.0.0
#r "nuget: QuokkaDev.SecurityHeaders, 4.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install QuokkaDev.SecurityHeaders as a Cake Addin
#addin nuget:?package=QuokkaDev.SecurityHeaders&version=4.0.0

// Install QuokkaDev.SecurityHeaders as a Cake Tool
#tool nuget:?package=QuokkaDev.SecurityHeaders&version=4.0.0

Quality Gate Status Coverage Maintainability Rating Technical Debt Duplicated Lines (%) publish workflow

QuokkaDev.SecurityHeaders

QuokkaDev.SecurityHeaders is a .NET middleware for adding OWASP security headers to your web applications. You can use online tools like https://securityheaders.com to check the status of your application against security headers.

Installing QuokkaDev.SecurityHeaders

You should install the package via the .NET command line interface

Install-Package QuokkaDev.SecurityHeaders

Using QuokkaDev.SecurityHeaders

Register the middleware using the extension methods. Call the extension method in the early phase of the pipeline so the security headers will be applied to all responses.

Please note that the middleware apply some default values for headers; if you don't want some headers you must explicitly overrides the values. You can override values programmatically or reading from configuration.

startup.cs

//Use headers with default values.
app.UseSecurityHeaders();

//Configure headers programmatically
app.UseSecurityHeaders(settings =>
{
    settings.XFrameOption = XFrameOption.deny;
    settings.XContentTypeOptions = XContentTypeOptions.nosniff;
    settings.UseContentSecurityPolicy = true;
    settings.UsePermissionPolicy = true;
    settings.XPermittedCrossDomainPolicies = XPermittedCrossDomainPolicies.none;
    settings.ReferrerPolicy = ReferrerPolicy.no_referrer;
    settings.CrossOriginEmbedderPolicy = CrossOriginEmbedderPolicy.require_corp;
    settings.CrossOriginOpenerPolicy = CrossOriginOpenerPolicy.same_origin;
    settings.CrossOriginResourcePolicy = CrossOriginResourcePolicy.same_origin;
    settings.ClearSiteData = new QuokkaDev.SecurityHeaders.ClearSitedata.ClearSiteData()
        .ClearCache()
        .ClearCookies()
        .ClearStorage();
    settings.ContentSecurityPolicy = ContentSecurityPolicyBuilder
        .New()
        .AddDefaultSrc( directive =>
        {
            directive.Self();
            directive.AddSource("https://my.custom.site");
        })
        .AddStyleSrc(directive =>
        {
            directive.Self();
            directive.UnsafeInline();
        })
        .Build();
    settings.PermissionPolicy = PermissionPolicyBuilder
        .New()
        .AddAccelerometer(directive => {
            directive.Self();
        })
        .Build();
});

//Use headers reading from values from configuration in a section named "SecurityHeaders"
app.UseSecurityHeaders(this.Configuration);

//You can also use a custom section name
app.UseSecurityHeaders(this.Configuration, "CustomSectionName");

//You can also read from configuration and programmatically override some values
app.UseSecurityHeaders(this.Configuration, "CustomSectionName", settings =>
{
    settings.XFrameOption = XFrameOption.none;
});

Available headers

X-Frame-Options

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • deny (default value)
  • sameorigin
app.UseSecurityHeaders(settings =>
{
    settings.XFrameOption = XFrameOption.sameorigin;
});
{
    "SecurityHeaders": {
        "XFrameOption": "sameorigin"
    }
}

X-Content-Type-Options

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • nosniff (default value)
app.UseSecurityHeaders(settings =>
{
    settings.XContentTypeOptions = XContentTypeOptions.nosniff;
});
{
    "SecurityHeaders": {
        "XContentTypeOptions": "nosniff"
    }
}

X-Permitted-Cross-Domain-Policies

Admitted values:

  • no_header (don't use header)
  • none (default value)
  • master_only
  • by_content_type
  • by_ftp_filename
  • all
app.UseSecurityHeaders(settings =>
{
    settings.XPermittedCrossDomainPolicies = XPermittedCrossDomainPolicies.none;
});
{
    "SecurityHeaders": {
        "XPermittedCrossDomainPolicies": "none"
    }
}

Referrer-Policy

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • no_referrer (default value)
  • no_referrer_when_downgrade
  • origin
  • origin_when_cross_origin
  • same_origin
  • strict_origin
  • strict_origin_when_cross_origin
  • unsafe_url
app.UseSecurityHeaders(settings =>
{
    settings.ReferrerPolicy = ReferrerPolicy.no_referrer;
});
{
    "SecurityHeaders": {
        "ReferrerPolicy": "no_referrer"
    }
}

Cross-Origin-Embedder-Policy

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • unsafe_none
  • require_corp (default value)
app.UseSecurityHeaders(settings =>
{
    settings.CrossOriginEmbedderPolicy = CrossOriginEmbedderPolicy.require_corp;
});
{
    "SecurityHeaders": {
        "CrossOriginEmbedderPolicy": "require_corp"
    }
}

Cross-Origin-Opener-Policy

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • unsafe_none
  • same_origin_allow_popups
  • same_origin (default value)
app.UseSecurityHeaders(settings =>
{
    settings.CrossOriginOpenerPolicy = CrossOriginOpenerPolicy.same_origin;
});
{
    "SecurityHeaders": {
        "CrossOriginOpenerPolicy": "same_origin"
    }
}

Cross-Origin-Resource-Policy

Admitted values:

  • no_header (don't use header)
  • none (don't use header, deprecated)
  • same_site
  • same_origin (default value)
  • cross_origin
app.UseSecurityHeaders(settings =>
{
    settings.CrossOriginResourcePolicy = CrossOriginResourcePolicy.same_origin;
});
{
    "SecurityHeaders": {
        "CrossOriginResourcePolicy": "same_origin"
    }
}

Clear-Site-Data

You can configure Clear-Site-Data passing a configured ClearSitedata object. You can clear site data for cache, storage and cookies. The default value for the header is

Clear-Site-Data: "cache", "cookies", "storage"
app.UseSecurityHeaders(settings =>
{
    settings.UseClearSiteData = true;
    settings.ClearSiteData = new ClearSitedata.ClearSiteData()
        .ClearCache()
        .ClearCookies()
        .ClearStorage();
});
{
    "SecurityHeaders": {
        "UseClearSiteData": true, //set to false for disable header
        "ClearSiteData": [ "cache", "cookies" , "storage"]
    }
}

Content-Security-Policy

You can configure Content-Security-Policy passing a configured ContentSecurityPolicy object. You can configure the object using configuration, using a "ready-to-use" string or using a ContentSecurityPolicyBuilder with fluent API. The default value for the header is:

Content-Security-Policy: default-src 'self'; object-src 'none'; child-src 'self'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content
//Configure CSP with a string
app.UseSecurityHeaders(settings =>
{
    settings.ContentSecurityPolicy = ContentSecurityPolicyBuilder
    .New("default-src 'self'; object-src 'none'")
    .Build();
});

//Configure CSP with fluent API
app.UseSecurityHeaders(settings =>
{
    settings.ContentSecurityPolicy = ContentSecurityPolicyBuilder
    .New()
    .AddDefaultSrc(directives => {
        directives.Self();
        directives.UnsafeInline();
        directives.AddSource("https://github.com");
    })
    .Build();
});

//Disable CSP header
app.UseSecurityHeaders(settings =>
{
    settings.UseContentSecurityPolicy = false;
});

If both a string and fluent API are used with ContentSecurityPolicyBuilder the string take the precedence

{
    "SecurityHeaders": {
        "UseContentSecurityPolicy": true //set to false for disable header
        "ContentSecurityPolicy": {
            "default-src": [ "'self'" ],
            "object-src": [ "'none'" ],
            "block-all-mixed-content": [ "" ],
            "child-src": [ "'self'" ],
            "frame-ancestors": [ "'none'" ],
            "upgrade-insecure-requests": [ "" ],
            "style-src": [ "'self'", "https://fonts.googleapis.com", "'nonce'" ],
            "font-src": [ "'self'", "https://fonts.gstatic.com" ],
            "script-src": [ "'self'", "'nonce'" ],
            "script-src-elem": [ "'self'", "'nonce'" ],
            "connect-src": [ "'self'" ],
            "prefetch-src": [ "'self'", "https://fonts.googleapis.com", "'nonce'" ]
        }
    }
}

Configure a directive calling the right method on the builder then adding all the allowed sources with AddSource(). Some utility methods like All(), None(), Self(), UnsafeInline(), UnsafeEval() can be used for standard values

If a directive take no extra values (like block-all-mixed-content) pass an array with an empty string in configuration file.

Ignore Urls

In some cases it can be useful disable the Content Security Policy for some URLs in your application. For example, if you use Swashbuckle.AspNetCore NuGet package it serve an index.html page with inline styles and scripts. You can bypass the problem using 'unsafe-inline' as a CSP value for styles and script but this makes the whole application much more insecure. You can disable CSP for the swagger endpoint using the property ContentSecurityPolicyIgnoreUrls and passing an array of path to ignore:

app.UseSecurityHeaders(settings =>
{
    settings.ContentSecurityPolicyIgnoreUrls = new string[] { "/swagger/index.html" };
});
{
    "SecurityHeaders": {
        "ContentSecurityPolicyIgnoreUrls": [ "/swagger/index.html" ]
    }
}
Nonce

If you need to use nonce for inline script and styles call AddSource("'nonce'") in fluent API or use the string "'nonce'" in configuration file.

Using nonce require that you configure a service for nonce generation in your startup file, so call the extension method:

services.AddNonceService();

The service inject a different nonce value in the header foreach request. Using this service you can easily build a TagHelper for RazorView pages:


using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Razor.TagHelpers;
using QuokkaDev.SecurityHeaders;

namespace MyProject.Web.TagHelpers
{
    [HtmlTargetElement(Attributes = "add-nonce")]
    public class NonceTagHelper : TagHelper
    {
        private readonly IHttpContextAccessor _contextAccessor;

        public NonceTagHelper(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.Attributes.RemoveAll("add-nonce");
            output.Attributes.Add(new TagHelperAttribute("nonce", new HtmlString(_contextAccessor.GetNonce())));
        }
    }
}
<script type="text/javascript" add-nonce>
    alert('now inline script works!!!');
</script>

Permissions-Policy

You can configure Permissions-Policy passing a configured PermissionPolicy object. You can configure the object using configuration, using a "ready-to-use" string or using a PermissionPolicyBuilder with fluent API. The default value for the header is:

Permissions-Policy: accelerometer=(),autoplay=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(self),usb=(),web-share=(),xr-spatial-tracking=()
//Configure permissions policy with a string
app.UseSecurityHeaders(settings =>
{
    settings.PermissionPolicy = PermissionPolicyBuilder
    .New("accelerometer=(),autoplay=(),camera=()")
    .Build();
});

//Configure permissions policy with fluent API
app.UseSecurityHeaders(settings =>
{
    settings.PermissionPolicy = PermissionPolicyBuilder
        .New()
        .AddCamera(directives => {
            directives.Self();
        })
        .Build();
});

//Disable permissions policy header
app.UseSecurityHeaders(settings =>
{
    settings.UsePermissionPolicy = false;
});

If both a string and fluent API are used with PermissionsPolicyBuilder the string take the precedence

{
    "SecurityHeaders": {
        "UsePermissionPolicy": true //set to false for disable header
        "PermissionPolicy": {
            "accelerometer": [""],
            "camera": [ "self" ],
            "display-capture": ["self", "https://mydomain"]
        }
    }
}

Configure a directive calling the right method on the builder then adding all the allowed sources with AddSource(). Utility method like Self() can be used for 'self' standard value

If a directive take no extra values pass an array with an empty string in configuration file.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.0.0 260 11/29/2023
4.0.0-rc4 82 11/29/2023
3.1.1-rc1 111 5/10/2023
3.1.0 999 12/21/2022
3.1.0-rc8 85 5/10/2023
3.1.0-rc7 125 12/21/2022
3.0.0 465 9/27/2022
3.0.0-rc6 147 9/27/2022
3.0.0-rc5 141 9/27/2022
3.0.0-alpha7 151 9/28/2022
2.1.1 394 9/12/2022
2.1.1-alpha8 154 9/27/2022
2.1.1-alpha0 133 9/13/2022
2.1.0 493 9/1/2022
2.1.0-alpha3 136 9/3/2022
2.0.0 373 8/29/2022
2.0.0-alpha2 148 9/2/2022
2.0.0-alpha0 139 8/30/2022
1.2.5 379 8/29/2022
1.2.4 385 8/25/2022
1.2.4-alpha0 142 8/26/2022
1.2.3 470 8/12/2022
1.2.3-alpha0 158 8/13/2022
1.2.2 399 8/12/2022
1.2.1 406 8/12/2022
1.2.0 412 8/12/2022
1.2.0-rc1 144 8/12/2022
1.1.1 410 8/11/2022
1.1.1-rc1 149 8/11/2022
1.1.1-alpha1 150 8/12/2022
1.1.0 403 8/11/2022
1.0.0 445 6/24/2022
1.0.0-alpha0 166 6/26/2022