Isaac.

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

  1. Start strict: Loosen if needed
  2. Use nonces: For inline scripts
  3. Report violations: Monitor CSP issues
  4. Update regularly: Security evolves
  5. 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.