Skip to main content

Task 30: Add Security Headers

Role

DevOps

Overview

Configure HTTP security headers to protect the MicDots application from common web vulnerabilities including XSS, clickjacking, MIME-sniffing, and other attacks. Implement OWASP-recommended security headers across all environments.

Objectives

  • Protect against Cross-Site Scripting (XSS) attacks
  • Prevent clickjacking attacks
  • Disable MIME-type sniffing
  • Enforce HTTPS connections (HSTS)
  • Control resource loading (CSP)
  • Implement referrer policy
  • Add permissions policy

Required Security Headers

Header Configuration

HeaderValuePurpose
Strict-Transport-Securitymax-age=31536000; includeSubDomains; preloadForce HTTPS for 1 year
X-Frame-OptionsDENYPrevent clickjacking
X-Content-Type-OptionsnosniffPrevent MIME-sniffing
X-XSS-Protection1; mode=blockEnable browser XSS filter (legacy)
Content-Security-PolicySee detailed policy belowControl resource loading
Referrer-Policystrict-origin-when-cross-originControl referrer information
Permissions-PolicySee detailed policy belowControl browser features

Content Security Policy (CSP)

Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://api.micdots.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;

Permissions Policy

Permissions-Policy:
geolocation=(),
microphone=(),
camera=(),
payment=(),
usb=(),
interest-cohort=()

Implementation

1. ASP.NET Core Middleware

public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;

public SecurityHeadersMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
// HSTS - Strict Transport Security
context.Response.Headers.Add(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload"
);

// X-Frame-Options - Prevent clickjacking
context.Response.Headers.Add("X-Frame-Options", "DENY");

// X-Content-Type-Options - Prevent MIME-sniffing
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");

// X-XSS-Protection (legacy browsers)
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");

// Content Security Policy
context.Response.Headers.Add(
"Content-Security-Policy",
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; " +
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
"font-src 'self' https://fonts.gstatic.com; " +
"img-src 'self' data: https:; " +
"connect-src 'self' https://api.micdots.com; " +
"frame-ancestors 'none'; " +
"base-uri 'self'; " +
"form-action 'self'; " +
"upgrade-insecure-requests;"
);

// Referrer Policy
context.Response.Headers.Add(
"Referrer-Policy",
"strict-origin-when-cross-origin"
);

// Permissions Policy
context.Response.Headers.Add(
"Permissions-Policy",
"geolocation=(), microphone=(), camera=(), payment=(), usb=(), interest-cohort=()"
);

// Remove server info headers
context.Response.Headers.Remove("Server");
context.Response.Headers.Remove("X-Powered-By");
context.Response.Headers.Remove("X-AspNet-Version");
context.Response.Headers.Remove("X-AspNetMvc-Version");

await _next(context);
}
}

2. Register Middleware

// Program.cs or Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<SecurityHeadersMiddleware>();

// Other middleware
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

3. Alternative: Using NWebsec Package

dotnet add package NWebsec.AspNetCore.Middleware
public void Configure(IApplicationBuilder app)
{
// HSTS
app.UseHsts(options => options
.MaxAge(days: 365)
.IncludeSubdomains()
.Preload()
);

// X-Frame-Options
app.UseXfo(options => options.Deny());

// X-Content-Type-Options
app.UseXContentTypeOptions();

// X-XSS-Protection
app.UseXXssProtection(options => options.EnabledWithBlockMode());

// Content Security Policy
app.UseCsp(options => options
.DefaultSources(s => s.Self())
.ScriptSources(s => s
.Self()
.UnsafeInline()
.UnsafeEval()
.CustomSources("https://cdn.jsdelivr.net")
)
.StyleSources(s => s
.Self()
.UnsafeInline()
.CustomSources("https://fonts.googleapis.com")
)
.FontSources(s => s
.Self()
.CustomSources("https://fonts.gstatic.com")
)
.ImageSources(s => s
.Self()
.Data()
.CustomSources("https:")
)
.ConnectSources(s => s
.Self()
.CustomSources("https://api.micdots.com")
)
.FrameAncestors(s => s.None())
.BaseUris(s => s.Self())
.FormActions(s => s.Self())
.UpgradeInsecureRequests()
);

// Referrer Policy
app.UseReferrerPolicy(options => options.StrictOriginWhenCrossOrigin());

// Remove server headers
app.Use(async (context, next) =>
{
context.Response.Headers.Remove("Server");
context.Response.Headers.Remove("X-Powered-By");
await next();
});
}

Nginx Configuration

server {
listen 443 ssl http2;
server_name micdots.com;

# SSL configuration
ssl_certificate /etc/letsencrypt/live/micdots.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/micdots.com/privkey.pem;

# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), interest-cohort=()" always;

# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.micdots.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests;" always;

# Remove server tokens
server_tokens off;
more_clear_headers Server;
more_clear_headers X-Powered-By;

location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Don't pass security headers from upstream
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
}
}

Environment-Specific Configuration

Development

{
"SecurityHeaders": {
"Enabled": true,
"ContentSecurityPolicy": {
"ReportOnly": true,
"AllowUnsafeInline": true,
"AllowUnsafeEval": true
}
}
}

Production

{
"SecurityHeaders": {
"Enabled": true,
"ContentSecurityPolicy": {
"ReportOnly": false,
"AllowUnsafeInline": false,
"AllowUnsafeEval": false
},
"HSTS": {
"MaxAge": 31536000,
"IncludeSubDomains": true,
"Preload": true
}
}
}

Testing & Validation

1. Online Security Header Scanners

# SecurityHeaders.com
https://securityheaders.com/?q=micdots.com

# Mozilla Observatory
https://observatory.mozilla.org/analyze/micdots.com

# SSL Labs
https://www.ssllabs.com/ssltest/analyze.html?d=micdots.com

2. Manual Testing with curl

# Check all security headers
curl -I https://micdots.com

# Check specific header
curl -I https://micdots.com | grep Strict-Transport-Security

# Verbose output
curl -v https://micdots.com 2>&1 | grep -E '<|>' | grep -E 'Strict-Transport-Security|X-Frame-Options|Content-Security-Policy'

3. Browser DevTools

// Check CSP violations in console
window.addEventListener('securitypolicyviolation', (e) => {
console.log('CSP Violation:', e.blockedURI, e.violatedDirective);
});

4. Automated Testing Script

#!/bin/bash

URL="https://micdots.com"

echo "Testing Security Headers for $URL"
echo "=================================="

headers=(
"Strict-Transport-Security"
"X-Frame-Options"
"X-Content-Type-Options"
"X-XSS-Protection"
"Content-Security-Policy"
"Referrer-Policy"
"Permissions-Policy"
)

for header in "${headers[@]}"; do
value=$(curl -s -I "$URL" | grep -i "^$header:" | cut -d' ' -f2-)
if [ -n "$value" ]; then
echo "✓ $header: $value"
else
echo "✗ $header: MISSING"
fi
done

CSP Reporting

Set up CSP Report Endpoint

[ApiController]
[Route("api/v1/csp")]
public class CspReportController : ControllerBase
{
private readonly ILogger<CspReportController> _logger;

public CspReportController(ILogger<CspReportController> logger)
{
_logger = logger;
}

[HttpPost("report")]
public IActionResult Report([FromBody] CspReportRequest report)
{
_logger.LogWarning(
"CSP Violation: {DocumentUri}, {BlockedUri}, {ViolatedDirective}",
report.CspReport.DocumentUri,
report.CspReport.BlockedUri,
report.CspReport.ViolatedDirective
);

return NoContent();
}
}

Update CSP Header to Include Reporting

Content-Security-Policy: ...existing-policy...; report-uri /api/v1/csp/report

Acceptance Criteria

  • All required security headers configured
  • HSTS header includes preload directive
  • CSP policy blocks unauthorized resources
  • X-Frame-Options prevents embedding
  • Server identification headers removed
  • Headers work in all environments
  • SecurityHeaders.com score: A+
  • Mozilla Observatory score: A+
  • SSL Labs score: A or A+
  • No CSP violations in browser console
  • Documentation updated
  • Configuration externalized
  • Monitoring/alerting for violations set up

Testing Checklist

Manual Testing

  • Run SecurityHeaders.com scan
  • Run Mozilla Observatory scan
  • Check headers in browser DevTools
  • Test CSP with inline scripts (should block)
  • Test iframe embedding (should be blocked)
  • Verify HSTS redirects HTTP to HTTPS
  • Test in multiple browsers

Automated Testing

  • Unit tests for middleware
  • Integration tests verify headers present
  • E2E tests check security behavior
  • Script to check headers on deploy

Estimated Time

6 hours

Dependencies

  • Task 26: HTTPS configuration must be complete
  • SSL certificate installed
  • Web server/reverse proxy configured

External Resources