🛡️ Security in .NET: Content Security Policy (CSP)
While input sanitization protects your database, Content Security Policy (CSP) acts as your application's "Bodyguard" in the browser.
Even if a malicious script bypasses validation filters, CSP instructs the browser:
Do not execute this script.
In this guide, we implement a production-ready Security Middleware that includes:
- Content Security Policy (CSP)
- HTTP Strict Transport Security (HSTS)
- Cross-Origin Isolation headers
- Swagger compatibility
1️⃣ Why CSP is Mandatory
Modern XSS attacks are highly sophisticated. Attackers may attempt to:
- Inject malicious inline <script> tags
- Load malicious JavaScript from external domains
- Execute dynamic code using
eval() - Inject scripts through compromised third-party libraries
A Content Security Policy is an HTTP response header that tells browsers which resources are trusted and allowed to execute.
By blocking inline scripts and restricting resource origins, CSP significantly reduces the risk of:
- Cross-Site Scripting (XSS)
- Data exfiltration attacks
- Malicious third-party script execution
2️⃣ The Professional Implementation
We implement CSP using custom middleware in ASP.NET Core.
Middleware ensures security headers are applied consistently across:
- API responses
- Error responses
- Static files
- Swagger documentation
Using context.Response.OnStarting guarantees headers are attached before the response body begins streaming.
SecurityHeadersMiddleware
namespace ProductApi.Middleware;
public class SecurityHeadersMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
context.Response.OnStarting(() =>
{
var headers = context.Response.Headers;
var isSwagger = context.Request.Path.StartsWithSegments("/swagger");
// 1. Basic Hardening
headers.TryAdd("X-Frame-Options", "DENY");
headers.TryAdd("X-Content-Type-Options", "nosniff");
headers.TryAdd("Referrer-Policy", "no-referrer");
// 2. Enforce HTTPS (HSTS)
if (context.Request.IsHttps)
{
headers.TryAdd(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload"
);
}
// 3. Conditional CSP Policy (Swagger Friendly)
if (isSwagger)
{
headers.TryAdd("Content-Security-Policy",
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
"style-src 'self' 'unsafe-inline'; " +
"img-src 'self' data:;");
}
else
{
headers.TryAdd("Content-Security-Policy",
"default-src 'self'; " +
"img-src 'self' data: https:; " +
"script-src 'self'; " +
"style-src 'self'; " +
"font-src 'self'; " +
"object-src 'none'; " +
"frame-ancestors 'none';");
}
// 4. Cross-Origin Isolation (Spectre Protection)
headers.TryAdd("Cross-Origin-Opener-Policy", "same-origin");
headers.TryAdd("Cross-Origin-Resource-Policy", "same-origin");
return Task.CompletedTask;
});
await next(context);
}
}
3️⃣ Breaking Down the CSP Policy
A CSP header is a set of rules that instruct the browser what is allowed to load and execute.
| Directive | Purpose |
|---|---|
default-src 'self' |
Only allow resources from the same origin |
script-src 'self' |
Blocks inline scripts and external malicious JavaScript |
style-src 'self' |
Prevents injected inline styles |
img-src 'self' data: |
Allows local images and base64 images |
object-src 'none' |
Blocks plugins such as Flash |
frame-ancestors 'none' |
Prevents clickjacking via iframe embedding |
4️⃣ Solving the Swagger Compatibility Problem
Swagger UI relies on inline scripts and styles, which are blocked by strict CSP rules.
We detect Swagger requests dynamically:
var isSwagger = context.Request.Path.StartsWithSegments("/swagger");
When Swagger is detected:
- A relaxed CSP policy is applied
- Inline scripts are temporarily allowed
- Developer experience remains smooth
All other API endpoints continue using a strict CSP policy.
- Disabling Swagger completely
- Protecting Swagger with authentication
- Restricting Swagger access via IP allow-list
5️⃣ Advanced Browser Isolation (COOP & CORP)
Modern browsers provide Cross-Origin Isolation headers to prevent memory-based attacks like Spectre.
| Header | Purpose |
|---|---|
| COOP | Prevents other websites from accessing your window object |
| CORP | Blocks other websites from embedding your resources |
🏁 Summary
By implementing this middleware, your API gains multiple layers of protection:
- XSS Protection – Malicious scripts are blocked
- HTTPS Enforcement – Secure transport is guaranteed
- Clickjacking Defense – UI cannot be embedded in iframes
- Memory Isolation – Prevents advanced browser attacks
- Developer Productivity – Swagger continues to function
- Input sanitization
- Output encoding
- Authentication
- HTTPS enforcement
Comments
Post a Comment