RFord.Projects.FluentContentSecurityPolicy 2.0.0

dotnet add package RFord.Projects.FluentContentSecurityPolicy --version 2.0.0
NuGet\Install-Package RFord.Projects.FluentContentSecurityPolicy -Version 2.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="RFord.Projects.FluentContentSecurityPolicy" Version="2.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add RFord.Projects.FluentContentSecurityPolicy --version 2.0.0
#r "nuget: RFord.Projects.FluentContentSecurityPolicy, 2.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 RFord.Projects.FluentContentSecurityPolicy as a Cake Addin
#addin nuget:?package=RFord.Projects.FluentContentSecurityPolicy&version=2.0.0

// Install RFord.Projects.FluentContentSecurityPolicy as a Cake Tool
#tool nuget:?package=RFord.Projects.FluentContentSecurityPolicy&version=2.0.0

Fluent Content Security Policy Builder

What is it?

This is a single accessible C# class designed to simplify generating CSP strings. You can use it anywhere a string is expected, or if you prefer to delay string evaluation until the last minute, you can simply generate the object, and call .Evaluate() when it is appropriate. If you follow the available Intellisense code-completion suggestions, you should get a spec conformant CSP string in return.

Specific enhancements over traditional static string

  • Supports punycoding international hostnames
  • Supports build-time retrieval of nonce values
  • Supports build-time SRI hashing of strings

Examples

Simple default policy

string x = ContentSecurityPolicyBuilder
            .BuildDefaultFetchPolicy()
            .AllowSelf()
            .Build()
            .Evaluate();

// x => default-src 'self'

Multiple fetch directives

string x = ContentSecurityPolicyBuilder
            .BuildDefaultFetchPolicy()
            .AllowSelf()

            .AndFor()
            .FetchDirectives()
            .OfPolicy<ImagePolicy>()
            .AllowAll()

            .AndFor()
            .FetchDirectives()
            .OfPolicy<MediaPolicy>()
            .AllowHost("example.org")
            .AllowHost("example.net")

            .AndFor()
            .FetchDirectives()
            .OfPolicy<ScriptPolicy>()
            .AllowHost("userscripts.example.com")
            .Build()
            .Evaluate();
            
// x => default-src 'self'; img-src *; media-src example.org example.net; script-src userscripts.example.com

Extremely contrived example

You can also define a policy ahead of time, inject it with your preferred DI framework, and build it as needed.

IContentSecurityPolicy unevaluated = ContentSecurityPolicyBuilder
                                       .BuildDefaultFetchPolicy()
                                       .AllowSelf()
                                       .AllowHost("https://*.example.com:12/path/to/file.js")
                                       .AllowHost("https://*.üüüüüü.com.de:12/path/to/file.js")
                                       .AllowHost("https://*.παράδειγμα.δοκιμή:12/path/to/file.js")

                                       .AndFor()
                                       .DocumentDirectives()
                                       .ConfigureBaseUri()
                                       .AllowSelf()
                                       .AllowHashOf(SriHash.Sha256, "doSubmit()")

                                       .AndFor()
                                       .FetchDirectives()
                                       .OfPolicy<WorkerPolicy>()
                                       .AllowHashOf(SriHash.Sha512, () => "testValue")

                                       .AndFor()
                                       .DocumentDirectives()
                                       .ConfigureSandbox()
                                       .GrantPermission(SandboxPermissions.Downloads)

                                       .AndFor()
                                       .FetchDirectives()
                                       .OfPolicy<ImagePolicy>()
                                       .AllowHost("example.com")

                                       .AndFor()
                                       .DocumentDirectives()
                                       .ConfigureSandbox()
                                       .GrantPermission(SandboxPermissions.Downloads)
                                       .GrantPermission(SandboxPermissions.SameOrigin)
                                       .GrantPermission(SandboxPermissions.PointerLock)

                                       .AndFor()
                                       .DocumentDirectives()
                                       .ConfigureBaseUri()
                                       .AllowSelf()

                                       .AndFor()
                                       .NavigationDirectives()
                                       .ConfigureFormAction()
                                       .AllowSelf()

                                       .AndFor()
                                       .NavigationDirectives()
                                       .ConfigureFrameAncestors()
                                       .AllowSelf()

                                       .AndFor()
                                       .NavigationDirectives()
                                       .ConfigureNavigateTo()
                                       .AllowSelf()

                                       .AndFor()
                                       .DocumentDirectives()
                                       .ConfigureBaseUri()
                                       .AllowSelf()

                                       .AndFor()
                                       .FetchDirectives()
                                       .OfPolicy<ImagePolicy>()
                                       .AllowSelf()

                                       .Build();

// register the above as a transient or singleton in your DI registration

// inject the object here via the IContentSecurityPolicy interface

// evaluate it
string x = unevaluated.Evaluate();

// x => default-src 'self' https://*.example.com:12/path/to/file.js https://*.xn--tdaaaaaa.com.de:12/path/to/file.js https://*.xn--hxajbheg2az3al.xn--jxalpdlp:12/path/to/file.js; base-uri 'self' 'sha256-jzgBGA4UWFFmpOBq0JpdsySukE1FrEN5bUpoK8Z29fY='; worker-src 'sha512-UBNdmiHnX8D5kMYOEAyZEJnM437eWylYaei68WvLN00+bXos8Kq6vtDphFIYvD7THNBYAIKjICzOGIFpHgTtZQ=='; sandbox allow-downloads allow-same-origin allow-pointer-lock; img-src example.com 'self'; form-action 'self'; frame-ancestors 'self'; navigate-to 'self'

Installing

If you want to use this in your project, install it from nuget:

Install-Package RFord.Projects.FluentContentPolicyBuilder

and reference it wherever appropriate in your project:

IContentSecurityPolicy policy = ContentSecurityPolicyBuilder
                                       .BuildDefaultFetchPolicy()
                                       ...
                                       ;

and start building!

References

I primarily used the following sources when building this:

TODO

  • Create NuGet package

  • Differentiate static directives vs dynamic directives, building the former when calling .AllowX(), and the latter when calling .Evaluate(). This is in contrast to the current behavior of deferring everything until final evaluation time.

  • Benchmarks

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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.
  • net6.0

    • No dependencies.

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
2.0.0 211 3/13/2023
1.0.1 176 3/12/2023
1.0.0 183 3/12/2023