Skip to content

Latest commit

 

History

History
272 lines (206 loc) · 21.8 KB

File metadata and controls

272 lines (206 loc) · 21.8 KB

Changelog

All notable changes to SafeWebCore will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.



1.8.1 — 2026-09-29

Added

  • SonarCloud Triage — how the analysis is scoped, how a new finding is triaged, and the ten findings that are deliberately accepted: eight Won't fix (six [Obsolete] members kept for backward compatibility, the instance method that cannot become static without breaking callers, and the analyzer package marker) and two False positive ([LoggerMessage]-generated code that the analyser cannot see). Indexed from docs/README.md and pointed at from the release-readiness checklist.

Changed

  • Dependency maintenance on the latest stable releases, with no API, default, preset or behavior change: SafeWebCore.JwtBearer moves to Microsoft.AspNetCore.Authentication.JwtBearer 10.0.12; the test projects to Microsoft.NET.Test.Sdk 18.10.1, xunit.v3 4.0.1, Microsoft.AspNetCore.TestHost 10.0.12 and coverlet.collector 10.1.0; and SafeWebCore.Testing to xunit.v3.assert 4.0.1. Microsoft.CodeAnalysis.PublicApiAnalyzers (5.6.0), Microsoft.CodeAnalysis.Analyzers / Microsoft.CodeAnalysis.CSharp (5.9.0), xunit.runner.visualstudio (4.0.0) and BenchmarkDotNet (0.15.8) were already on their latest stable release; Microsoft.AspNetCore.Mvc.Testing stays floating on 10.0.* and resolves to 10.0.12.
  • Internal deduplication of the fraud detectors and the security-header pipeline — the pen-test signal scoring, the authorization-check notification flow and the path-policy resolution existed as byte-identical copies in GeoCulturalConsistencyDetector / WesternImpersonationDetector and in NetSecureHeadersMiddleware / NetSecureHeadersDiagnosticsService. They now live once, in the internal PenTestSignalAnalyzer and PathPolicyResolver helpers that both call sites use, so a score, a throttle rule or a policy-resolution rule can only change in one place. No public API, default, preset, configuration path or behavior change.
  • Internal code-quality cleanup with no behavior change: the repeated CSP source literals in SecurePresets, CspOptions and CrossOriginPolicyBuilder now name one private constant per file, and the path-policy lookup walks the list by index instead of allocating an enumerator per request. Every emitted header value, directive and policy-resolution outcome is identical.

Companion packages

  • SafeWebCore.FraudDetection 1.1.1 — the same internal cleanup; no public API, default or behavior change.
  • SafeWebCore.JwtBearer 1.0.1 — Microsoft.AspNetCore.Authentication.JwtBearer dependency updated from 10.0.11 to 10.0.12 (the package now requires that patch or newer). Packaging parity with core and FraudDetection finally lands here too: a .snupkg symbol package with SourceLink and deterministic builds, release notes in the nuspec, and the badge-corrected packaged README.md that --skip-duplicate kept skipping at 1.0.0.
  • SafeWebCore.Analyzers and SafeWebCore.Testing 1.0.0-preview.2 — the SonarCloud cleanup, plus xunit.v3.assert 4.0.1 in Testing. Both stay preview.

Compatibility

  • ✅ 100% backwards compatible — internal refactors, dependency maintenance and documentation only. No public API, default, preset, configuration path or behavior change, so a 1.8.0 configuration keeps behaving exactly as before.
  • The public API baselines are unchanged: all three PublicAPI.Unshipped.txt files still hold only #nullable enable, so no symbol moved from unshipped to shipped in this release.

1.8.0 — 2026-09-27

Added

  • SafeWebCoreMetrics.SecurityEventSinkFailures (safewebcore.security_event_sink_failures_total) and SafeWebCoreFraudMetrics.FraudEventSinkFailures (safewebcore.fraud_event_sink_failures_total) — a sink failure that a dispatcher isolates is now counted instead of disappearing.
  • SecurityEventDispatcher(IEnumerable<ISecurityEventSink>, SafeWebCoreMetrics?) — overload for the failure counter. The existing single-argument constructor keeps working.
  • RiskLevel.Unclassified (= 4, appended last) — the level for a verdict the library does not recognize, so an unknown verdict is never reported as Low.
  • SafeWebCore.FraudDetection moves to the three-part version 1.1.0 (was the four-part 1.0.0.0, which NuGet normalizes to the already-published 1.0.0) and reaches packaging parity with core: icon.png inside the package, a .snupkg symbol package with SourceLink, and PackageReleaseNotes in the nuspec metadata.

Companion package: SafeWebCore.JwtBearer 1.0.0 (published 2026-09-10)

  • New companion module: SafeWebCore.JwtBearer — makes a misconfigured JWT authority fail loud (or fail fast) at startup instead of silently returning 401 for everything. Solves dotnet/aspnetcore#67991 (reported by Stephan van Rooij) today, while the .NET team schedules the fix for .NET 12 Planning. Implements AddJwtBearerAuthorityValidation, AddJwtBearerHardening, and the one-liner AddSafeWebCoreJwtBearer.
  • SafeWebCore.JwtBearer token hardening — optional: require signed tokens / reject alg: none, algorithm allow-list, typ header checks (JWT/at+jwt), audience/issuer enforcement, maximum clock skew and token lifetime, jti/nbf/iat requirements.
  • SafeWebCore.JwtBearer runtime metadata logging — wraps the OpenID Connect configuration manager so metadata retrieval failures are logged at Error (4xx) / Warning level during runtime, not only at startup.
  • SafeWebCore.JwtBearer empty-JWKS detection — a discovery document that loads but contains no signing keys is now a permanent configuration error: Error log + startup throw when FailFast, down-gradable to a Warning via RequireSigningKeys = false.
  • SafeWebCore.JwtBearer optional PeriodicValidationInterval — background re-validation of the authority while the app runs (never throws; permanent → Error, transient → Warning). Closes the last-known-good observability gap for identity-provider outages after a healthy start.
  • examples/JwtBearerDemo — runnable reproduction of issue #67991 (broken vs. fixed behavior) and StephanReproIntegrationTests proving both sides.
  • Note: this module reached nuget.org on 2026-09-10 as SafeWebCore.JwtBearer 1.0.0, from the same workspace commits recorded here; the repository has no tag for that publish, so its changes appear in a CHANGELOG section for the first time. The v1.8.0 release train carries SafeWebCore.JwtBearer 1.0.0 unchanged, so NuGet skips it as a duplicate.

Security

  • SecurityEventDispatcher isolates a throwing ISecurityEventSink per sink instead of letting it end delivery for every sink registered after it. All three call sites discard the returned task, so a bare loop lost the remaining events and surfaced the failure only as an unobserved task exception; a failing sink can no longer mute the others.
  • Verdict mappings now fail closed: RiskScore.FromScoreAndVerdict maps an unrecognized verdict to RiskLevel.Unclassified (never Low) and the shared verdict-to-action mapping maps it to RecommendedAction.BlockRequest (never NoAction). An unrecognized verdict is therefore never reported as safe.
  • AdditionalHeaders may no longer name a header the library owns (HSTS, X-Frame-Options, CSP, NEL, Reporting-Endpoints, and the rest of the typed set). Startup validation fails with the options scope and a Fix: that points at CustomPolicies / IHeaderPolicy, because assigning the response header indexer replaced the library value — for CSP including the per-request {nonce} substitution, which silently dropped the nonce authorization of every script and style the app emits.

Compatibility

  • ✅ 100% backwards compatible — the new counters, the SecurityEventDispatcher overload and RiskLevel.Unclassified are additive, and existing registrations plus PathPolicies.Add(new PathPolicyOptions { ... }) replacement semantics behave exactly as in 1.7.0.
  • ⚠️ Intentional tightening — a configuration that named a library-owned header in AdditionalHeaders now fails at startup instead of silently replacing the library value. Move the entry to CustomPolicies (IHeaderPolicy) when the replacement is deliberate.
  • ⚠️ A consumer switch over RiskLevel without a default arm needs one new arm for Unclassified; every other enum member keeps its value.

1.7.0 — 2026-08-04

Added

  • SecurePresets.OwaspApi() and AddNetSecureHeadersOwaspApiPreset(...) — preset aligned with the OWASP API Security Top 10 recommended response-header hardening for API endpoints (HSTS, nosniff, no-referrer, no cross-domain policies, server/X-Powered-By removal, browser-document headers disabled).
  • SecurePresets.OwaspApiPath(...) — path policy helper for OWASP API-aligned headers on specific prefixes (default /api).
  • SecurePresets.NSwag() and AddNetSecureHeadersNSwagPreset(...) — preset for the NSwag UI (Rico Sutter's NSwag / NSwagStudio). NSwag is stricter than classic Swagger UI: assets load from https://unpkg.com/nswag/ and CSP uses nonces + 'strict-dynamic' with no 'unsafe-inline'.

Security

  • Resolved issue #3: NetSecureHeadersOptions.PathPolicy(...) now inherits all unspecified settings from the global configuration instead of falling back to library defaults — preventing accidental security header downgrades (e.g. a weaker HSTS on /api).
  • ApplyPreset(...) and Clone() are now public — the official inheritance mechanism for building path policies and custom presets from an existing options instance.

Compatibility

  • ✅ 100% backwards compatible — all new presets, path-policy inheritance APIs, and registration helpers are additive and opt-in. Existing PathPolicies.Add(new PathPolicyOptions { ... }) replacement semantics are unchanged.

1.6.0 — 2026-07-25

Added

  • AddNetSecureHeadersFromConfiguration(IConfiguration, string sectionName = "NetSecureHeaders") and AddNetSecureHeadersFromConfiguration(IConfigurationSection) for direct configuration binding into NetSecureHeadersOptions.
  • AddNetSecureHeadersForEnvironment(...) and AddNetSecureHeadersStrictAPlusForEnvironment(...) as opt-in rollout helpers that default CSP to report-only mode outside production unless the caller overrides it.
  • MapSafeWebCoreDiagnostics(...) as an opt-in endpoint for previewing effective headers, matched path policies, and CSP mode.
  • Internal diagnostics service infrastructure to compute effective SafeWebCore policy output without changing runtime behavior.
  • SafeWebCore.Analyzers package (initial preview) to start the v1.5 tooling roadmap.

Observability (v1.6)

  • Added opt-in metrics using System.Diagnostics.Metrics (meter names: SafeWebCore and SafeWebCore.FraudDetection).
    • Core counters: headers_applied_total, csp_violations_total, path_policy_matches_total.
    • Fraud counters: fraud_analyses_total, fraud_events_by_risk_total (tagged risk_level), fraud_events_by_verdict_total (tagged verdict).
    • Metrics are registered automatically but only produce data when observed (OpenTelemetry, Prometheus, etc.).
  • FraudEvent.Report now includes the additive Risk (RiskScore + RiskLevel) property.
  • LoggingFraudEventSink now includes RiskLevel in the default log message.
  • Existing ISecurityEventSink / SecurityEventDispatcher and IFraudEventSink / FraudEventDispatcher remain the primary event extensibility points.
  • Tests added using MeterListener (unit + integration through real middleware).

Fraud action pipeline (v1.6 Epic 9.2)

  • Added additive IFraudEventSink + FraudEvent for reacting to fraud analysis results (logging, metrics, webhooks, custom actions).
    • Register sinks with AddFraudEventSink<T>().
    • A default LoggingFraudEventSink is registered automatically (emits at Information level when enabled).
    • Both GeoCulturalConsistencyDetector and the legacy WesternImpersonationDetector dispatch events after producing a FraudReport.
    • FraudReport and Analyze(...) contract are unchanged — this is purely additive.
    • This delivers the first concrete part of Epic 9.2 (fraud action pipeline abstractions).

Tooling (v1.5)

  • Added SafeWebCore.Analyzers package (initial preview) for build-time diagnostics.
    • SWC001: Registration without UseNetSecureHeaders()
    • SWC002: Permanent UseCspReportOnly = true
    • SWC003: 'unsafe-inline' without nonce
    • SWC004: Overly broad CSP sources (*, bare https:, unsafe-eval)
  • Added SafeWebCore.Testing package (preview) with:
    • Header assertions (AssertHasSecurityHeaders, AssertHasCspEnforceMode, etc.)
    • CSP and nonce assertions
    • Test host / bootstrap helpers for quick integration test setup
  • Added practical recipe documentation under docs/recipes/ (MVC+CDN, Swagger, Blazor, Report-Only rollout, Reverse Proxy/IIS).

Changed

  • Startup validation messages now include concrete remediation guidance for CSP report-only misuse, normalized path-prefix collisions, duplicate additional headers, and invalid reporting endpoint URLs.

Tests

  • Added coverage for configuration binding, environment-aware registration helpers, improved validation messages, and diagnostics endpoint behavior.

Documentation

  • Expanded docs/getting-started.md with configuration-based setup and environment-aware rollout guidance.
  • Expanded docs/advanced-configuration.md with diagnostics endpoint usage, actionable validation examples, and updated troubleshooting guidance.
  • Updated README.md, PACKAGE.md, and docs/README.md to surface the completed v1.4 feature set clearly.

Compatibility

  • ✅ 100% backwards compatible — all new registration helpers, diagnostics features, and validation improvements are additive and opt-in.

1.3.5 — 2026-05-09

Added

  • RemoveXPoweredBy option (defaults to false; enabled automatically by all Strict A+ presets) to remove the X-Powered-By response header.
  • First-class support for the NEL (Network Error Logging) header via new options EnableNel and NelValue.
  • ReportingEndpoints integration example for NEL in documentation.

Changed

  • Server and X-Powered-By header removal now consistently use HttpResponse.OnStarting for the highest possible reliability against headers added late in the pipeline (Kestrel, hosting layer, other middleware).
  • Strict A+ (and derived presets: Api, Mvc, Blazor, SpaReverseProxy) no longer emit four Permissions-Policy directives that securityheaders.com and Chromium-based browsers flag as invalid:
    • identity-credentials-get
    • otp-credentials
    • publickey-credentials-create
    • window-management
  • Permissions-Policy in StrictAPlus now only contains scanner-safe, currently recognised Chromium feature tokens while keeping a strong deny-all posture.

Documentation

  • Major expansion of "Server Header Removal" and new dedicated "X-Powered-By Header Removal" sections in docs/security-headers.md.
  • Clear explanation of OnStarting behaviour and real-world hosting limitations (IIS AspNetCoreModule, reverse proxies, CDNs).
  • Added concrete web.config example for complete IIS removal.
  • Updated all version references, quick-start examples, and "What's New" sections across README.md, PACKAGE.md, docs/getting-started.md, and docs/presets.md.
  • New feature highlights added to PackageReleaseNotes in the .csproj.

Fixed

  • Eliminated "invalid directive" warnings reported by securityheaders.com for Permissions-Policy when using Strict A+ presets.
  • Ensured X-Powered-By is removed by default when using AddNetSecureHeadersStrictAPlus() and related preset helpers.

No breaking changes — fully backward compatible. All new options default to previous behaviour.


1.3.0 — 2026-05-02

Changed

  • StrictAPlus preset — Permissions-Policy browser-compatibility cleanup

    The StrictAPlus (and all presets derived from it: Api, Mvc, Blazor, SpaReverseProxy) no longer emits Permissions-Policy tokens that are absent from the current spec. Chromium-based browsers log each unrecognised token as a console warning, which surfaced as noise for consumers of the preset.

    Removed (8 stale tokens — no longer in the Permissions Policy spec):

    Token Reason
    ambient-light-sensor Removed from spec; not recognised by Chromium
    battery Was in old Feature Policy; never added to Permissions Policy
    cross-origin-isolated Document Policy concept, not a Permissions Policy feature
    document-domain Proposed but removed before standardisation
    execution-while-not-rendered Removed from spec
    execution-while-out-of-viewport Removed from spec
    navigation-override Removed from spec
    sync-xhr Deprecated and removed from spec

    Added (7 modern tokens — standardised 2022–2024):

    Token Standardised since
    clipboard-read Chrome 76 / Permissions Policy v2
    clipboard-write Chrome 76 / Permissions Policy v2
    identity-credentials-get Chrome 116 (FedCM)
    local-fonts Chrome 103
    otp-credentials Chrome 93 (WebOTP)
    publickey-credentials-create Chrome 108 (WebAuthn L2)
    window-management Chrome 100 (replaces window-placement)

    The preset now emits 28 recognised feature tokens — all denied — providing full coverage without browser console noise.

Tests

  • Added StrictAPlusPermissionsPolicyIncludesModernTokens — asserts all 7 new tokens are present.
  • Added StrictAPlusPermissionsPolicyExcludesStaleTokens — asserts all 8 removed tokens are absent, preventing regressions.

Compatibility

  • ✅ 100% backwards compatible with v1.0.0 – v1.2.0
  • The PermissionsPolicyValue string changes, but it is still a valid Permissions-Policy header value. Any application that overrides PermissionsPolicyValue manually (as the stopgap pattern) is unaffected.

1.1.0 — 2025-06-28

Added

  • HttpContext.GetCspNonce() extension method — Discoverable way to retrieve the per-request CSP nonce without magic strings. Available via using SafeWebCore.Extensions;.
    var nonce = HttpContext.GetCspNonce();
  • NonceService.TryWriteNonce(Span<char>, out int) — Zero-allocation overload that writes the nonce directly into a caller-provided buffer. Ideal for high-throughput scenarios or writing directly into response buffers.
    Span<char> buffer = stackalloc char[NonceService.NonceLength];
    if (nonceService.TryWriteNonce(buffer, out int written))
    {
        // Use buffer[..written] — no heap allocation
    }
  • NonceService.NonceLength constant — Public constant (44) for the length of a generated nonce string. Eliminates magic numbers when pre-allocating buffers.

Changed

  • CSP template is now pre-built once in the middleware constructor instead of being rebuilt on every request. Only the lightweight string.Replace("{nonce}", nonce) runs per-request. This significantly reduces per-request allocations.
  • CspOptions.Build() uses StringBuilder — Replaced List<string> + interpolated string allocations + string.Join with a pre-sized StringBuilder(512). Eliminates ~20 intermediate string allocations per call.
  • CspReportMiddleware now passes CancellationToken — ReadToEndAsync uses context.RequestAborted for proper cancellation when clients disconnect.
  • CspNonceAttribute uses C# pattern matching — Collapsed nested conditionals into a single is string { Length: > 0 } nonce pattern expression.
  • Preset application extracted to ApplyPreset helper — Internal NetSecureHeadersOptions.ApplyPreset() method consolidates the 20+ line property copy into a single reusable call. Adding new options in the future requires updating only one place.

Compatibility

  • ✅ 100% backwards compatible with v1.0.0
  • All existing public APIs (AddNetSecureHeadersStrictAPlus, UseNetSecureHeaders, CspBuilder, [CspNonce], CSP reporting) remain unchanged
  • No breaking changes to method signatures, behavior, or configuration
  • All 40 existing tests pass without modification

1.0.0 — 2025-06-15

Added

  • Strict A+ preset — AddNetSecureHeadersStrictAPlus() for one-line A+ configuration on securityheaders.com
  • Fluent CspBuilder with full CSP Level 3 (W3C Recommendation) directive coverage
  • CSP Level 4 support — Trusted Types (require-trusted-types-for, trusted-types), fenced-frame-src
  • Per-request cryptographic nonce generation with stackalloc + RandomNumberGenerator (zero heap allocations)
  • [CspNonce] action filter attribute for Razor view nonce injection
  • Built-in CSP violation reporting middleware (/csp-report endpoint)
  • Extensible IHeaderPolicy interface for custom header policies
  • Full security header suite: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COEP, COOP, CORP, X-DNS-Prefetch-Control, X-Permitted-Cross-Domain-Policies
  • Server header removal
  • Comprehensive documentation and test suite