Security Headers
The application includes configurable security header middleware that applies common HTTP response headers to help reduce browser-based attack surface. The middleware is registered through the application extension pattern so Program.cs can remain clean and minimal.
Security headers are registered during service configuration:
builder.Services.AddApplicationSecurityHeaders(builder.Configuration);
They are applied through the standard application pipeline:
app.UseApplicationPipeline();
The pipeline calls:
app.UseApplicationSecurityHeaders();
v1.0 Security Header Contract
This contract applies when ProjectTemplate:SecurityHeaders:Enabled is true and the request path does not match ExcludedPathPrefixes.
| Header | Default | Contract | Configuration |
|---|---|---|---|
X-Content-Type-Options |
nosniff |
Required when security headers are enabled and the request path is not excluded | Not individually configurable |
X-Frame-Options |
DENY |
Required when security headers are enabled and the request path is not excluded | Not individually configurable |
Referrer-Policy |
strict-origin-when-cross-origin |
Required when security headers are enabled and the request path is not excluded | Not individually configurable |
X-Permitted-Cross-Domain-Policies |
none |
Required when security headers are enabled and the request path is not excluded | Not individually configurable |
Cross-Origin-Opener-Policy |
same-origin |
Configurable group | Controlled by EnableCrossOriginHeaders |
Cross-Origin-Resource-Policy |
same-origin |
Configurable group | Controlled by EnableCrossOriginHeaders |
Permissions-Policy |
camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self) |
Configurable | Controlled by EnablePermissionsPolicy and PermissionsPolicy |
Content-Security-Policy |
default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; |
Configurable | Controlled by EnableContentSecurityPolicy and ContentSecurityPolicy |
X-XSS-Protection |
Not emitted | Intentionally omitted | Not supported |
The middleware intentionally does not add X-XSS-Protection because that header is obsolete and can create inconsistent behavior in modern browsers.
Intentional Opt-Outs
The following settings reduce or remove default browser hardening and should be used intentionally:
| Setting | Effect | Recommended use |
|---|---|---|
Enabled = false |
Disables all application security headers | Only when an upstream reverse proxy, gateway, or host platform applies equivalent headers |
EnableContentSecurityPolicy = false |
Removes CSP | Temporary troubleshooting or applications that must define CSP elsewhere |
EnablePermissionsPolicy = false |
Removes Permissions-Policy | Only when browser feature policy is managed elsewhere |
EnableCrossOriginHeaders = false |
Removes COOP and CORP | Applications that intentionally integrate cross-origin windows or resources |
ExcludedPathPrefixes |
Skips all security headers for matching paths | Infrastructure endpoints such as /health and /metrics |
Configuration
Security headers can be configured from appsettings.json:
"ProjectTemplate": {
"SecurityHeaders": {
"Enabled": true,
"EnableContentSecurityPolicy": true,
"EnablePermissionsPolicy": true,
"EnableCrossOriginHeaders": true,
"ContentSecurityPolicy": "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline';",
"PermissionsPolicy": "camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)",
"ExcludedPathPrefixes": [
"/health",
"/metrics"
]
}
}
Configuration Options
| Option | Purpose |
|---|---|
Enabled |
Enables or disables the security header middleware. |
EnableContentSecurityPolicy |
Controls whether the Content-Security-Policy header is applied. |
EnablePermissionsPolicy |
Controls whether the Permissions-Policy header is applied. |
EnableCrossOriginHeaders |
Controls whether Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy are applied. |
ContentSecurityPolicy |
Defines the application Content Security Policy value. |
PermissionsPolicy |
Defines the Permissions Policy value. |
ExcludedPathPrefixes |
Skips security header application for matching request path prefixes. |
Environment-Specific Behavior
The default configuration is intentionally conservative. Applications created from this template can loosen or override headers in environment-specific settings files such as appsettings.Development.json.
For example, a local development configuration may temporarily disable CSP while troubleshooting script or style loading:
"ProjectTemplate": {
"SecurityHeaders": {
"EnableContentSecurityPolicy": false
}
}
Production applications should use the strongest policy possible for the deployed application. In particular, production deployments should avoid broad CSP allowances such as unsafe-inline where practical and should only allow trusted script, style, image, frame, and connection sources.
Excluded Paths
The default excluded paths are:
[
"/health",
"/metrics"
]
These paths are commonly used by infrastructure, monitoring tools, or container orchestration systems. Additional paths can be excluded if needed.
Testing Response Headers
Run the application and inspect the response headers from the root endpoint:
curl -k -I https://localhost:5001/
Expected headers include:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
X-Permitted-Cross-Domain-Policies: none
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline';
The exact CSP and Permissions-Policy values may differ if overridden by configuration.