Web applications are increasingly targeted by Cross-Site Scripting (XSS) and data injection attacks. Even if you sanitize inputs, malicious scripts can still find ways to run in browsers.
A Content Security Policy (CSP) is a powerful security feature supported by modern browsers that mitigates these risks by restricting what resources (scripts, styles, images, fonts, etc.) can load on your application pages.
What is CSP?
Content Security Policy (CSP) is an HTTP response header that tells the browser which resources are allowed to load and execute.
Example CSP header
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com; style-src 'self' fonts.googleapis.com
This policy
Only allows scripts from the same origin ('self'
) and cdn.example.com
.
Only allows styles from 'self'
and Google Fonts.
Blocks all other external resources.
Why CSP Matters
Prevents XSS: Attackers can’t inject inline <script>
tags or load scripts from unauthorized domains.
Restricts Data Exfiltration: Stops attackers from sending stolen data to malicious servers.
Improves Security Posture: Adds defense-in-depth, even if other controls fail.
Enabling CSP in ASP.NET Core (Razor Pages / MVC)
ASP.NET Core doesn’t enforce CSP by default. You configure it by adding response headers.
1. Using Middleware
In Program.cs
(ASP.NET Core 6/7/8 style):
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Add CSP header middleware
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-Security-Policy",
"default-src 'self'; " +
"script-src 'self' https://cdnjs.cloudflare.com; " +
"style-src 'self' https://fonts.googleapis.com; " +
"font-src 'self' https://fonts.gstatic.com; " +
"img-src 'self' data:; " +
"object-src 'none'; " +
"frame-ancestors 'none'; " +
"upgrade-insecure-requests;");
await next();
});
app.MapRazorPages();
app.Run();
This enforces CSP for every response.
2. Using the NWebsec
Middleware (Recommended)
NWebsec is a popular security library for ASP.NET Core that makes CSP and other security headers easier to configure.
Install the package
dotnet add package NWebsec.AspNetCore.Middleware
Then configure CSP in Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseCsp(options => options
.DefaultSources(s => s.Self())
.ScriptSources(s => s.Self().CustomSources("https://cdnjs.cloudflare.com"))
.StyleSources(s => s.Self().CustomSources("https://fonts.googleapis.com"))
.FontSources(s => s.Self().CustomSources("https://fonts.gstatic.com"))
.ImageSources(s => s.Self().CustomSources("data:"))
.ObjectSources(s => s.None())
.FrameAncestors(s => s.None())
.UpgradeInsecureRequests()
);
app.MapControllers();
app.MapRazorPages();
app.Run();
This is cleaner and avoids manual string concatenation.
3. Handling Inline Scripts and Styles
By default, CSP blocks inline JavaScript and CSS, including:
Options to allow them (not recommended, but sometimes needed):
Example with nonce
app.Use(async (context, next) =>
{
var nonce = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
context.Items["CSPNonce"] = nonce;
context.Response.Headers.Add("Content-Security-Policy",
$"script-src 'self' 'nonce-{nonce}'");
await next();
});
Razor Page
<script nonce="@Context.Items["CSPNonce"]">
console.log('This inline script is allowed by CSP nonce');
</script>
4. Reporting Violations
You can instruct the browser to report CSP violations:
context.Response.Headers.Add("Content-Security-Policy",
"default-src 'self'; report-uri /csp-report");
Define an endpoint in your app to log reports:
[HttpPost("/csp-report")]
public IActionResult CspReport([FromBody] object report)
{
// Log to DB, file, or monitoring system
return Ok();
}
Example Policy for Razor Pages / MVC
A balanced CSP policy for most ASP.NET Core apps:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdnjs.cloudflare.com 'nonce-xyz';
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data:;
object-src 'none';
frame-ancestors 'none';
upgrade-insecure-requests;
Best Practices
Use NWebsec for easier configuration.
Prefer nonces over 'unsafe-inline'
.
Start with Report-Only mode (Content-Security-Policy-Report-Only
) to test before enforcing.
Block object-src
and frame-ancestors
unless explicitly needed.
Regularly review external CDN usage.
Conclusion
Content Security Policy (CSP) significantly strengthens the security of Razor Pages and MVC applications by reducing the risk of XSS and other injection attacks. ASP.NET Core makes it easy to implement CSP through middleware or libraries like NWebsec. With careful configuration, you can balance strong security with application functionality.