Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
ASP.NET Core Security in .NET 11: Automatic CSRF Protection with Fetch Metadata, Device Bound Session Credentials and TLS Channel Binding
.NET 11 adds CSRF protection, on by default for apps built with WebApplication.CreateBuilder, that checks the Sec-Fetch-Site and Origin headers; yet only form-reading endpoints enforce the verdict and DisableAntiforgery turns it off too. We cover the decision table, origins trusted through CORS, a middleware applying the same rules on .NET 10, experimental DBSC, TLS channel binding, unified authorization metadata and a migration checklist.
Observing Security Events in ASP.NET Core: Authentication, Authorization and Identity Metrics, Audit Trails and Alerts
.NET 10's authentication, authorization and Identity metrics count 401s, 403s and account lockouts but deliberately carry no user or policy name; who did what and when is the audit trail's job. We collect the metrics with OpenTelemetry and Prometheus, verify the real labels with a test, write alert rules and build a hash-chained audit trail that detects tampering.
Kestrel and Request Limits: Body Size, Header Timeout, Request Timeouts and Settings Against Slow Clients
By default Kestrel allows a 28.6 MB body, 30 seconds for headers and unlimited request duration, and a request timeout stops nothing unless the CancellationToken is carried. We read the real defaults from code and, with measurements, cover body, header, form and JSON limits, RequestHeadersTimeout and MinRequestBodyDataRate against slow clients, the request timeouts middleware and the split of work between Kestrel and the reverse proxy.
Antiforgery in Depth: CSRF Protection with Cookie Authentication, SPAs and Minimal APIs
ASP.NET Core's antiforgery middleware does not reject requests; it writes the result to a feature, and in minimal APIs only form binding enforces it, so cookie-authenticated JSON endpoints accept token-less requests with 200. With real output we cover the token pair internals, Angular's XSRF-TOKEN pattern, an endpoint filter that enforces validation, refreshing the token after login and deliberate use of DisableAntiforgery.
Emitting Security Headers and Nonce-Based CSP from ASP.NET Core: HSTS Preload, COOP/COEP/CORP, Permissions-Policy and a Reporting Endpoint
A nonce-based CSP changes on every request and depends on the response type, so it belongs in the app rather than Nginx, and the HTML must not be cached at any layer. We build one ASP.NET Core middleware with separate API and HTML header sets, nonce injection into Angular's index.html, Report-Only with a size- and rate-limited reporting endpoint, the HSTS preload risk and COOP/COEP/CORP, with real header output.
Rate Limiting in Depth: Algorithms, Partition Keys, Chained Limiters and Multiple Instances
ASP.NET Core rate limiters live in process memory: two instances double the limit, and behind a proxy without the real IP everyone lands in one partition. We compare fixed window, sliding window and token bucket under the same traffic, then show queue order, partition keys, CreateChained, 429 instead of the default 503 with Retry-After, the shared-policy trap and a per-user-name login limit with real output.
Data Protection in Depth: The Key Ring, Rotation, Key Storage, Encrypting Keys and Multiple Instances
Random logouts and empty-bodied 400s in a multi-instance ASP.NET Core app usually come from a separate Data Protection key ring per instance. Using real logs, we cover the key ring lifetime, rotation and revocation, the purpose hierarchy, file, Redis and database stores, encrypting keys with a certificate and the role of SetApplicationName.
Inside Authorization: Policy Providers, Requirement Handlers, IAuthorizationMiddlewareResultHandler and Testing Policies
On every request AuthorizationMiddleware merges endpoint metadata into one policy, authenticates, runs the handlers and turns the result into 401 or 403. We show OR between handlers, AND between requirements and the veto of Fail() with real output, then build a dynamic policy provider, IAuthorizationRequirementData, a 403 with a ProblemDetails body and an endpoint × user test matrix.
What Changed in Frontend Security from Angular 11 to 22 and in Browsers
From Angular 11 to 22 most security features arrived in patches rather than new majors, so auditing an old project means checking the exact version, not the major. In this post we verify the version of each feature from Trusted Types to autoCsp and SSR allowedHosts from package tarballs, show in headless Chrome that 22.0.8 does not send the XSRF header, collect the browser changes and produce a runnable audit script.
Hardening the npm Supply Chain: Lifecycle Scripts, Release Cooldowns, Provenance and Trusted Publishing
Hardening the npm supply chain rests on three pillars: limiting install scripts with an allow list, letting new versions wait a few days, and removing publish tokens with trusted publishing. In this post we try npm 11 and 12's allowScripts policy, pnpm's allowBuilds and minimumReleaseAge, npm's min-release-age, npm audit signatures output and OIDC-based trusted publishing with real installs against a local registry.
Angular SSR Security: allowedHosts, Host Header Validation, TransferState and Secrets Leaking into Bundles
In Angular SSR the server resolves relative HttpClient URLs against the incoming request's Host header, so fill allowedHosts with explicit names, trust proxy headers only behind a trusted proxy and do not derive the API address from Host. On a local SSR server we show SSRF, the 2026 advisories, fields leaking into TransferState, a nonce-based CSP under SSR and secrets ending up in bundles and source maps, all with real output.
Third-Party Scripts, iframes and postMessage: sandbox, frame-ancestors, Permissions-Policy and Safe Messaging
Third-party code added with a script tag runs in your origin with your authority; move it into a sandboxed iframe on its own origin, close your page to framing with the frame-ancestors header, switch off unused APIs with Permissions-Policy and validate origin, source window and schema in postMessage. We show each step with real output from headless Chrome and Vitest in a local three-origin lab.