Skip to content
AI-assisted, verified against source

Changelog v3.6.0 (2025-02-01)

Version 3.6.0 (2025-02-01)

Full Changelog

New Feature: Security Headers Middleware

Added configurable security headers middleware to protect against common web vulnerabilities. The middleware adds HTTP security headers to all responses:

  • X-Content-Type-Options - Prevents MIME-sniffing attacks (default: nosniff)
  • X-Frame-Options - Prevents clickjacking attacks (default: DENY, skipped if Antiforgery is enabled)
  • Referrer-Policy - Controls referrer information (default: strict-origin-when-cross-origin)
  • Content-Security-Policy - Defines approved content sources (configurable)
  • Permissions-Policy - Controls browser feature access (configurable)
  • Cross-Origin-Opener-Policy - Controls document sharing with popups
  • Cross-Origin-Embedder-Policy - Controls cross-origin resource loading
  • Cross-Origin-Resource-Policy - Controls resource sharing cross-origin

Configuration:

jsonc
jsonc
//
// Security Headers: Adds HTTP security headers to all responses to protect against common web vulnerabilities.
// These headers instruct browsers how to handle your content securely.
// Note: X-Frame-Options is automatically handled by the Antiforgery middleware when enabled (see Antiforgery.SuppressXFrameOptionsHeader).
// Reference: https://owasp.org/www-project-secure-headers/
//
"SecurityHeaders": {
  //
  // Enable security headers middleware. When enabled, configured headers are added to all HTTP responses.
  //
  "Enabled": false,
  //
  // X-Content-Type-Options: Prevents browsers from MIME-sniffing a response away from the declared content-type.
  // Recommended value: "nosniff"
  // Set to null to not include this header.
  //
  "XContentTypeOptions": "nosniff",
  //
  // X-Frame-Options: Controls whether the browser should allow the page to be rendered in a <frame>, <iframe>, <embed> or <object>.
  // Values: "DENY" (never allow), "SAMEORIGIN" (allow from same origin only)
  // Note: This header is SKIPPED if Antiforgery is enabled (Antiforgery already sets X-Frame-Options: SAMEORIGIN by default).
  // Set to null to not include this header.
  //
  "XFrameOptions": "DENY",
  //
  // Referrer-Policy: Controls how much referrer information should be included with requests.
  // Values: "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin",
  //         "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"
  // Recommended: "strict-origin-when-cross-origin" (send origin for cross-origin requests, full URL for same-origin)
  // Set to null to not include this header.
  //
  "ReferrerPolicy": "strict-origin-when-cross-origin",
  //
  // Content-Security-Policy: Defines approved sources of content that the browser may load.
  // Helps prevent XSS, clickjacking, and other code injection attacks.
  // Example: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
  // Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
  // Set to null to not include this header (recommended to configure based on your application needs).
  //
  "ContentSecurityPolicy": null,
  //
  // Permissions-Policy: Controls which browser features and APIs can be used.
  // Example: "geolocation=(), microphone=(), camera=()" disables these features entirely.
  // Example: "geolocation=(self), microphone=()" allows geolocation only from same origin.
  // Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy
  // Set to null to not include this header.
  //
  "PermissionsPolicy": null,
  //
  // Cross-Origin-Opener-Policy: Controls how your document is shared with cross-origin popups.
  // Values: "unsafe-none", "same-origin-allow-popups", "same-origin"
  // Set to null to not include this header.
  //
  "CrossOriginOpenerPolicy": null,
  //
  // Cross-Origin-Embedder-Policy: Prevents a document from loading cross-origin resources that don't explicitly grant permission.
  // Values: "unsafe-none", "require-corp", "credentialless"
  // Required for SharedArrayBuffer and high-resolution timers (along with COOP: same-origin).
  // Set to null to not include this header.
  //
  "CrossOriginEmbedderPolicy": null,
  //
  // Cross-Origin-Resource-Policy: Indicates how the resource should be shared cross-origin.
  // Values: "same-site", "same-origin", "cross-origin"
  // Set to null to not include this header.
  //
  "CrossOriginResourcePolicy": null
}

New Feature: Forwarded Headers Middleware

Added support for processing proxy headers when running behind a reverse proxy (nginx, Apache, Azure App Service, AWS ALB, Cloudflare, etc.). This is critical for getting the correct client IP address and protocol.

  • X-Forwarded-For - Gets real client IP instead of proxy IP
  • X-Forwarded-Proto - Gets original protocol (http/https)
  • X-Forwarded-Host - Gets original host header

Configuration:

jsonc
jsonc
//
// Forwarded Headers: Enables the application to read proxy headers (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host).
// CRITICAL: Required when running behind a reverse proxy (nginx, Apache, Azure App Service, AWS ALB, Cloudflare, etc.)
// Without this, the application sees the proxy's IP instead of the client's real IP, and HTTP instead of HTTPS.
// Security Warning: Only enable if you're behind a trusted proxy. Malicious clients can spoof these headers.
// Reference: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer
//
"ForwardedHeaders": {
  //
  // Enable forwarded headers middleware. Must be placed FIRST in the middleware pipeline.
  //
  "Enabled": false,
  //
  // Limits the number of proxy entries that will be processed from X-Forwarded-For.
  // Default is 1 (trust only the immediate proxy). Increase if you have multiple proxies in a chain.
  // Set to null to process all entries (not recommended for security).
  //
  "ForwardLimit": 1,
  //
  // List of IP addresses of known proxies to accept forwarded headers from.
  // Example: ["10.0.0.1", "192.168.1.1"]
  // If empty and KnownNetworks is also empty, forwarded headers are accepted from any source (less secure).
  //
  "KnownProxies": [],
  //
  // List of CIDR network ranges of known proxies.
  // Example: ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"] for private networks
  // Useful when proxy IPs are dynamically assigned within a known range.
  //
  "KnownNetworks": [],
  //
  // List of allowed values for the X-Forwarded-Host header.
  // Example: ["example.com", "www.example.com"]
  // If empty, any host is allowed (less secure). Helps prevent host header injection attacks.
  //
  "AllowedHosts": []
}

New Feature: Health Check Endpoints

Added health check endpoints for container orchestration (Kubernetes, Docker Swarm) and monitoring systems:

  • /health - Overall health status (combines all checks)
  • /health/ready - Readiness probe with optional PostgreSQL connectivity check
  • /health/live - Liveness probe (always returns healthy if app is running)

Configuration:

jsonc
jsonc
//
// Health Checks: Provides endpoints for monitoring application health, used by container orchestrators (Kubernetes, Docker Swarm),
// load balancers, and monitoring systems to determine if the application is running correctly.
// Three types of checks are supported:
//   - /health: Overall health status (combines all checks)
//   - /health/ready: Readiness probe - is the app ready to accept traffic? (includes database connectivity)
//   - /health/live: Liveness probe - is the app process running? (always returns healthy if app responds)
// Reference: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks
//
"HealthChecks": {
  //
  // Enable health check endpoints.
  //
  "Enabled": false,
  //
  // Cache health check responses server-side in memory for the specified duration.
  // Cached responses are served without re-executing the endpoint. 
  // Value is in PostgreSQL interval format (e.g., '5 seconds', '1 minute', '30s', '1min').
  // Set to null to disable caching. Query strings are ignored to prevent cache-busting.
  //
  "CacheDuration": "5 seconds",
  //
  // Path for the main health check endpoint that reports overall status.
  // Returns "Healthy", "Degraded", or "Unhealthy" with HTTP 200 (healthy/degraded) or 503 (unhealthy).
  //
  "Path": "/health",
  //
  // Path for the readiness probe endpoint.
  // Kubernetes uses this to know when a pod is ready to receive traffic.
  // Includes database connectivity check when IncludeDatabaseCheck is true.
  // Returns 503 Service Unavailable if database is unreachable.
  //
  "ReadyPath": "/health/ready",
  //
  // Path for the liveness probe endpoint.
  // Kubernetes uses this to know when to restart a pod.
  // Always returns Healthy (200) if the application process is responding.
  // Does NOT check database - a slow database shouldn't trigger a container restart.
  //
  "LivePath": "/health/live",
  //
  // Include PostgreSQL database connectivity in health checks.
  // When true, the readiness probe will fail if the database is unreachable.
  //
  "IncludeDatabaseCheck": true,
  //
  // Name for the database health check (appears in detailed health reports).
  //
  "DatabaseCheckName": "postgresql",
  //
  // Require authentication for health check endpoints.
  // When true, all health endpoints require a valid authenticated user.
  // Security Consideration: Health endpoints can reveal information about your infrastructure
  // (database connectivity, service status). Enable this if your health endpoints are publicly accessible.
  // Note: Kubernetes/Docker health probes may need to authenticate if this is enabled.
  //
  "RequireAuthorization": false,
  //
  // Apply a rate limiter policy to health check endpoints.
  // Specify the name of a policy defined in RateLimiterOptions.Policies.
  // Security Consideration: Prevents denial-of-service attacks targeting health endpoints.
  // Set to null to disable rate limiting on health endpoints.
  // Example: "fixed" or "bucket" (must match a policy name from RateLimiterOptions).
  //
  "RateLimiterPolicy": null
}

Added new dependency: AspNetCore.HealthChecks.NpgSql for PostgreSQL health checks.

New Feature: PostgreSQL Statistics Endpoints

Added HTTP endpoints for monitoring PostgreSQL database statistics, useful for debugging, performance analysis, and operational monitoring:

  • /stats/routines - Function/procedure performance statistics from pg_stat_user_functions (call counts, execution times)
  • /stats/tables - Table statistics from pg_stat_user_tables (tuple counts, sizes, scan counts, vacuum info)
  • /stats/indexes - Index statistics from pg_stat_user_indexes (scan counts, definitions)
  • /stats/activity - Current database activity from pg_stat_activity (active sessions, queries, wait events)

Output formats:

  • HTML (default) - HTML table with Excel-compatible formatting for direct browser copy-paste
  • JSON - JSON array with camelCase property names

Configuration:

jsonc
jsonc
//
// PostgreSQL Statistics Endpoints
// Exposes PostgreSQL statistics through HTTP endpoints for monitoring and debugging.
// Provides access to pg_stat_user_functions, pg_stat_user_tables, pg_stat_user_indexes, and pg_stat_activity.
//
"Stats": {
  //
  // Enable PostgreSQL statistics endpoints.
  //
  "Enabled": false,
  //
  // Cache stats responses server-side in memory for the specified duration.
  // Cached responses are served without re-executing the endpoint.
  // Value is in PostgreSQL interval format (e.g., '5 seconds', '1 minute', '30s', '1min').
  // Set to null to disable caching. Query strings are ignored to prevent cache-busting.
  //
  "CacheDuration": "5 seconds",
  //
  // Apply a rate limiter policy to stats endpoints.
  // Specify the name of a policy defined in RateLimiterOptions.Policies.
  // Set to null to disable rate limiting on stats endpoints.
  //
  "RateLimiterPolicy": null,
  //
  // Use a specific named connection for stats queries.
  // When null, uses the default connection string.
  // Useful when you want to query stats from a different database or use read-only credentials.
  //
  "ConnectionName": null,
  //
  // Require authentication for stats endpoints.
  // Security Consideration: Stats endpoints can reveal sensitive information about your database
  // (table sizes, query patterns, active sessions). Enable this for production environments.
  //
  "RequireAuthorization": false,
  //
  // Restrict access to specific roles.
  // When null or empty, any authenticated user can access (if RequireAuthorization is true).
  // Example: ["admin", "dba"] - only users with admin or dba role can access.
  //
  "AuthorizedRoles": [],
  //
  // Output format for stats endpoints: "json" or "html".
  // - json: JSON array
  // - html: HTML table, Excel-compatible for direct browser copy-paste (default)
  //
  "OutputFormat": "html",
  //
  // Filter schemas using PostgreSQL SIMILAR TO pattern.
  // When null, all schemas are included.
  // Example: "public|myapp%" - includes 'public' and schemas starting with 'myapp'.
  //
  "SchemaSimilarTo": null,
  //
  // Path for routine (function/procedure) performance statistics.
  // Returns data from pg_stat_user_functions including call counts and execution times.
  // Note: Requires track_functions = 'pl' or 'all' in postgresql.conf.
  // Enable with: alter system set track_functions = 'all'; select pg_reload_conf();
  // Or set track_functions = 'all' directly in postgresql.conf and restart/reload.
  //
  "RoutinesStatsPath": "/stats/routines",
  //
  // Path for table statistics.
  // Returns data from pg_stat_user_tables including tuple counts, sizes, scan counts, and vacuum info.
  //
  "TablesStatsPath": "/stats/tables",
  //
  // Path for index statistics.
  // Returns data from pg_stat_user_indexes including scan counts and index definitions.
  //
  "IndexesStatsPath": "/stats/indexes",
  //
  // Path for current database activity.
  // Returns data from pg_stat_activity showing active sessions, queries, and wait events.
  // Security Consideration: Shows currently running queries which may contain sensitive data.
  //
  "ActivityPath": "/stats/activity"
}

Comments