Security Headers in Web Apps
Protect applications with security headers.
By EMEPublished: February 20, 2025
security headerscsphstsweb securityheaders
A Simple Analogy
Security headers are like locks on your doors. Each header adds a layer of protection against different attack types.
Why Security Headers?
- XSS prevention: Content Security Policy
- Clickjacking prevention: X-Frame-Options
- HTTPS enforcement: HSTS
- Compression attacks: Disable compression
- MIME sniffing: Content-Type validation
Essential Headers
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
public async Task InvokeAsync(HttpContext context)
{
// Prevent MIME sniffing
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
// Prevent clickjacking
context.Response.Headers.Add("X-Frame-Options", "DENY");
// Enable XSS protection (older browsers)
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
// Enforce HTTPS
context.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
// Referrer policy
context.Response.Headers.Add("Referrer-Policy", "strict-origin-when-cross-origin");
await _next(context);
}
}
// Register middleware
app.UseMiddleware<SecurityHeadersMiddleware>();
Content Security Policy
// Strict CSP
var csp = "default-src 'self'; " +
"script-src 'self' 'unsafe-inline'; " + // Allow inline scripts
"style-src 'self' 'unsafe-inline'; " +
"img-src 'self' data: https:; " +
"font-src 'self'; " +
"connect-src 'self' api.example.com; " +
"frame-ancestors 'none'; " +
"base-uri 'self'; " +
"form-action 'self'";
context.Response.Headers.Add("Content-Security-Policy", csp);
// Report violations
var cspReport = csp + "; report-uri /api/csp-report";
CORS Headers
// Allow specific origins
var origins = new[] { "https://app.example.com", "https://admin.example.com" };
app.UseCors(policy => policy
.WithOrigins(origins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithExposedHeaders("X-Total-Count", "X-Page-Number")
.SetPreflightMaxAge(TimeSpan.FromHours(1))
);
Cookie Security
// Secure cookies
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.HttpOnly = HttpOnlyPolicy.Always;
options.Secure = CookieSecurePolicy.Always;
options.SameSite = SameSiteMode.Strict;
});
app.UseCookiePolicy();
// Session cookie
var sessionCookie = builder.Services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
Security Policy Header
// Permissions Policy (replaces Feature-Policy)
context.Response.Headers.Add("Permissions-Policy",
"geolocation=(), " +
"microphone=(), " +
"camera=(), " +
"payment=(), " +
"usb=(), " +
"accelerometer=(), " +
"gyroscope=(), " +
"magnetometer=()");
Best Practices
- Start strict: Loosen if needed
- Use nonces: For inline scripts
- Report violations: Monitor CSP issues
- Update regularly: Security evolves
- Test headers: Verify deployment
Related Concepts
- OWASP Top 10
- Security testing
- Web vulnerabilities
- Penetration testing
Summary
Security headers provide defense-in-depth against common web attacks. Implement CSP, HSTS, CORS, and cookie policies to harden applications.