Skip to content

Repository files navigation

🛡️ SafeWebCore

NuGetNuGet Downloads.NET 10License: MITsecurityheaders.comCSPSponsor

SafeWebCore is a lightweight, high-performance .NET 10 middleware library that adds security headers to your ASP.NET Core applications. It targets an A+ rating on securityheaders.com out of the box — zero configuration required.

Current version: 1.7.0


✨ Features

  • 🔒 A+ in one lineAddNetSecureHeadersStrictAPlus() configures the strictest security headers instantly
  • 🧭 App-profile presets — ready-made profiles for API, MVC, Blazor, and SPA reverse-proxy apps
  • 🛠️ Fully customAddNetSecureHeaders(opts => { ... }) gives you complete control over every header
  • ⚙️ Configuration bindingAddNetSecureHeadersFromConfiguration(...) binds NetSecureHeadersOptions directly from configuration
  • 🌦️ Environment-aware rollout — opt-in helpers can default CSP to report-only outside production for safer rollout
  • 🧩 Nonce-based CSP — per-request cryptographic nonces for script-src and style-src
  • 🧷 Razor nonce TagHelpers — auto-inject nonce attributes on <script> and <style> when available
  • 🛣️ Path-based policies — apply different security profiles per route prefix with longest-prefix matching
  • 🎯 Endpoint metadata overrides — skip headers or force CSP report-only per endpoint
  • 🧪 Startup configuration validation — invalid combinations fail fast during startup
  • 📝 CSP Report-Only support — ship policies safely before enforcing
  • 🧱 Typed policy builders — strongly typed builders for Referrer-Policy, Permissions-Policy, and COEP/COOP/CORP values
  • 🧰 Optional additional headers — opt-in support for Origin-Agent-Cluster, X-Robots-Tag, and Clear-Site-Data
  • 📋 Full CSP Level 3 (W3C Recommendation) — all directives including worker-src, manifest-src, frame-src, script-src-elem/attr, style-src-elem/attr, report-to, nonce/hash support, strict-dynamic
  • 🔮 CSP Level 4 ready — Trusted Types (require-trusted-types-for, trusted-types), fenced-frame-src (Privacy Sandbox)
  • 🎯 Fluent CSP Builder — type-safe, chainable API with full XML documentation for every directive
  • Zero-allocation nonce generationstackalloc + RandomNumberGenerator on the hot path, plus TryWriteNonce(Span<char>) for fully heap-free scenarios
  • 🔍 HttpContext.GetCspNonce() — discoverable extension method to retrieve the per-request nonce
  • 🛑 Server header removal — hides server technology from attackers
  • 🔌 Extensible — add custom IHeaderPolicy implementations for any header
  • 📊 CSP violation reporting — built-in middleware for /csp-report endpoint using Reporting API v1
  • 🔍 Diagnostics previewMapSafeWebCoreDiagnostics(...) for an opt-in JSON preview of effective headers, path-policy resolution, and CSP mode
  • 📈 Opt-in metricsSystem.Diagnostics.Metrics counters for core middleware and fraud detection
  • 🚨 Fraud action pipelineIFraudEventSink / FraudEvent for reacting to fraud analysis results (logging, webhooks, custom actions)
  • 📦 Companion packagesSafeWebCore.FraudDetection, SafeWebCore.Analyzers (preview), and SafeWebCore.Testing (preview)
  • 📖 Recipe docs — practical integration guides under docs/recipes/
  • Actionable startup validation — remediation guidance for CSP mode, path prefixes, additional headers, and reporting endpoints

Typed builders for non-CSP headers

usingSafeWebCore.Builder;builder.Services.AddNetSecureHeaders(opts =>{opts.ReferrerPolicyValue=newReferrerPolicyBuilder().StrictOriginWhenCrossOrigin().Build();opts.PermissionsPolicyValue=newPermissionsPolicyBuilder().Disable(PermissionsFeature.Camera).Disable(PermissionsFeature.Microphone).AllowSelf(PermissionsFeature.Geolocation).Build();varcrossOrigin=newCrossOriginPolicyBuilder().CoepRequireCorp().CoopSameOrigin().CorpSameOrigin().Build();opts.CoepValue=crossOrigin.Coep;opts.CoopValue=crossOrigin.Coop;opts.CorpValue=crossOrigin.Corp;});

Optional additional headers

builder.Services.AddNetSecureHeaders(opts =>{opts.EnableOriginAgentCluster=true;opts.OriginAgentClusterValue="?1";opts.EnableXRobotsTag=true;opts.XRobotsTagValue="noindex, nofollow";opts.EnableClearSiteData=true;opts.ClearSiteDataValue="\"cache\", \"cookies\", \"storage\"";});

CSP Compliance

StandardStatusCoverage
CSP Level 3 (W3C Recommendation)✅ FullAll 22 directives, nonce/hash, strict-dynamic, report-to
CSP Level 4 (Emerging)✅ ReadyTrusted Types, fenced-frame-src (Privacy Sandbox)

🆕 What's New in v1.7.0

v1.7.0 is a security hardening and presets release — fully backwards compatible with v1.6.0 and earlier.

ImprovementDetail
Path policy inheritancePathPolicy(...) now inherits the global configuration — only explicitly set values override (resolves issue #3, prevents HSTS/CSP downgrades on path-specific endpoints)
Public inheritance APIApplyPreset(...) and Clone() are now public — build path policies and custom presets from an existing options instance
OWASP API presetAddNetSecureHeadersOwaspApiPreset() aligned with the OWASP API Security Top 10 response-header hardening
NSwag presetAddNetSecureHeadersNSwagPreset() for Rico Sutter's NSwag UI with nonce-based CSP and no 'unsafe-inline' (stricter than Swagger)

See the full CHANGELOG for details.


🚀 Quick Start

1. Install

dotnet add package SafeWebCore

2. One-line A+ setup (recommended)

usingSafeWebCore.Extensions;varbuilder=WebApplication.CreateBuilder(args);// Adds ALL security headers with the strictest A+ configurationbuilder.Services.AddNetSecureHeadersStrictAPlus();varapp=builder.Build();app.UseNetSecureHeaders();app.MapGet("/",()=>"Hello, secure world!");app.Run();

That's it! Your application now returns these headers on every response:

HeaderValue
Strict-Transport-Securitymax-age=63072000; includeSubDomains; preload
X-Frame-OptionsDENY
X-Content-Type-Optionsnosniff
Referrer-Policyno-referrer
Permissions-PolicyAll recognized features denied (scanner-safe)
Cross-Origin-Embedder-Policyrequire-corp
Cross-Origin-Opener-Policysame-origin
Cross-Origin-Resource-Policysame-origin
X-DNS-Prefetch-Controloff
X-Permitted-Cross-Domain-Policiesnone
Content-Security-PolicyNonce-based, strict-dynamic, Trusted Types
Server(removed)
X-Powered-By(removed)

3. Strict A+ with customization

The preset is intentionally strict. Relax only what your app needs. CSP directives are space-separated — add multiple origins in a single string:

builder.Services.AddNetSecureHeadersStrictAPlus(opts =>{// Multiple CDNs — just separate with spacesopts.Csp=opts.Cspwith{ImgSrc="'self' https://cdn1.example.com https://cdn2.example.com data:"};// Multiple directives at once using 'with { ... }'opts.Csp=opts.Cspwith{ConnectSrc="'self' https://api.example.com wss://ws.example.com",FontSrc="'self' https://fonts.gstatic.com https://cdn.example.com"};// Non-CSP headers are simple string propertiesopts.ReferrerPolicyValue="strict-origin-when-cross-origin";});

💡 Tip: Each CSP directive is one string with space-separated sources. Use a single with { ... } block to change multiple directives at once.

4. Full manual configuration

For complete control, use AddNetSecureHeaders with the fluent CSP builder:

usingSafeWebCore.Builder;usingSafeWebCore.Extensions;builder.Services.AddNetSecureHeaders(opts =>{opts.EnableHsts=true;opts.HstsValue="max-age=31536000; includeSubDomains";opts.EnableXFrameOptions=true;opts.XFrameOptionsValue="SAMEORIGIN";opts.ReferrerPolicyValue="strict-origin-when-cross-origin";// Use the fluent CSP builderopts.Csp=newCspBuilder().DefaultSrc("'none'").ScriptSrc("'nonce-{nonce}' 'strict-dynamic' https:").StyleSrc("'nonce-{nonce}'").ImgSrc("'self' https: data:").FontSrc("'self' https://fonts.gstatic.com").ConnectSrc("'self' wss://realtime.example.com").FrameAncestors("'none'").BaseUri("'none'").FormAction("'self'").UpgradeInsecureRequests().Build();});

🧭 v1.5 Tooling (Current Workspace)

The current workspace includes the completed v1.5 tooling features (additive, opt-in, 100% backward compatible):

Analyzers (SafeWebCore.Analyzers)

  • SWC001: Registration without UseNetSecureHeaders()
  • SWC002: Permanent UseCspReportOnly = true
  • SWC003: 'unsafe-inline' without nonce
  • SWC004: Overly broad CSP sources

Testing Helpers (SafeWebCore.Testing)

  • AssertHasSecurityHeaders()
  • AssertHasCspEnforceMode() / AssertHasCspReportOnlyMode()
  • AssertHasNonceInCsp() / AssertHasNoNonceInCsp()
  • Bootstrap helpers for TestServer

See docs/recipes/ for practical examples.


🧭 v1.2 Milestone Progress

The following features are now implemented from the v1.2 plan.

CSP Report-Only mode

builder.Services.AddNetSecureHeaders(opts =>{opts.UseCspReportOnly=true;});

This emits Content-Security-Policy-Report-Only instead of enforce-mode Content-Security-Policy.

Path-based policy overrides

builder.Services.AddNetSecureHeaders(opts =>{opts.PathPolicies.Add(newPathPolicyOptions{PathPrefix="/api",Options=newNetSecureHeadersOptions{ReferrerPolicyValue="no-referrer",UseCspReportOnly=true}});});

Path policies are matched by prefix and the longest matching prefix wins.

Startup validation

SafeWebCore validates options during startup and fails fast for invalid configurations, for example:

  • UseCspReportOnly = true while EnableCsp = false
  • duplicate path prefixes (normalized)
  • empty path policy prefixes

Razor nonce TagHelpers

Register the TagHelpers in your Razor _ViewImports.cshtml:

@addTagHelper *, SafeWebCore

Then use normal tags; nonce is added automatically when available:

<script>console.log("nonce is injected automatically");</script><style>body { font-family: sans-serif; }
</style>

🔑 Using CSP Nonces in Razor Views

SafeWebCore generates a unique cryptographic nonce per request. Use it in your scripts and styles:

With the [CspNonce] attribute

usingSafeWebCore.Attributes;[CspNonce]publicclassHomeController:Controller{publicIActionResultIndex()=>View();}
<!-- In your Razor view --><scriptnonce="@ViewData["CspNonce"]">console.log("This script is allowed by CSP");</script><stylenonce="@ViewData["CspNonce"]">body { font-family: sans-serif; }
</style>

Direct access via GetCspNonce() extension (v1.1.0+)

usingSafeWebCore.Extensions;// In Minimal APIapp.MapGet("/page",(HttpContextctx)=>{varnonce=ctx.GetCspNonce();returnResults.Content($"<script nonce=\"{nonce}\">console.log('nonce ok');</script>","text/html");});// In a controller actionpublicIActionResultIndex(){ViewData["CspNonce"]=HttpContext.GetCspNonce();returnView();}

⚡ Benchmarks

SafeWebCore ships a BenchmarkDotNet suite covering nonce generation, CSP header assembly, typed policy builders, preset instantiation, the middleware pipeline, and CSP report parsing.

cd benchmarks/SafeWebCore.Benchmarks
dotnet run -c Release

See docs/benchmarks.md for scenario descriptions, running instructions, and result interpretation.


📖 Examples

Three complete, runnable ASP.NET Core applications demonstrating different integration patterns:

ExampleFrameworkKey Features
MinimalApiMinimal APIOne-line A+ setup, inline nonce, CSP reporting, health probes
MvcAppMVC + Razor ViewsTyped policy builders, path policies, nonce TagHelpers, controller attributes
ApiServiceWeb API ControllersCustom CSP report sink, endpoint overrides, API preset

Each example is fully functional out of the box — just dotnet run from the example directory.

# Try each examplecd examples/MinimalApi && dotnet run
cd examples/MvcApp && dotnet run
cd examples/ApiService && dotnet run

See examples/README.md for a detailed overview and feature matrix.


📚 Documentation

GuideDescription
Getting StartedInstallation, minimal setup, and verifying your headers
ExamplesThree complete sample projects (Minimal API, MVC, Web API)
Security HeadersEvery security header explained with values and rationale
CSP ConfigurationCSP builder, nonces, directives, and common scenarios
PresetsStrict A+ and app-profile presets, customization examples
Advanced ConfigurationCustom policies, CSP reporting, endpoint overrides, troubleshooting
BenchmarksRunning benchmarks and interpreting results

About

a security library for .net web development

Resources

Contributing

Stars

6 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages