Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
OWASP API Security Top 10: What Changed from 2019 to 2023 and Reading Old Reports in Today's Terms
In the 2023 edition Excessive Data Exposure and Mass Assignment merged into BOPLA, API2, API4 and API9 were renamed, Injection and Logging left the list, and sensitive business flows, SSRF and unsafe consumption were added; so old findings are mapped by meaning, not by number. A mapping table, a small tool that translates old reports and shows unassessed categories, and what we'll do when a new edition arrives.
Continuously Testing and Monitoring API Security: Authorization Regression, OpenAPI-Driven Scanning and Abuse Telemetry
To keep API security in place continuously, you put the controls into a test pyramid, run an OpenAPI-driven scanner only against your own environment and turn its findings into regression tests, and measure rejected requests per tenant. Contract gaps and two 500s found by Schemathesis, a systematic fix with RespectNullableAnnotations, OpenTelemetry metrics and a one-page checklist.
API8 and API9: Misconfiguration and Inventory — Using OpenAPI as an Inventory, Deprecation/Sunset Headers and Shadow APIs
Against API8 you tie an API-specific checklist to tests that run in the Production environment; against API9 you use the OpenAPI document generated at build time as a committed inventory and retire old versions with the RFC 9745 Deprecation and RFC 8594 Sunset headers. CORS and middleware order, catching an unannounced endpoint with git diff, and a time zone trap.
API7 and API10: APIs That Talk to the Outside World — Webhooks, Outbound URL Validation and Not Trusting Third-Party Responses
You validate a user-supplied webhook URL by shape at registration and, at connect time, on every resolved address with SocketsHttpHandler.ConnectCallback, and you treat third-party responses like user input. A DNS rebinding imitation, delivery without redirects, a signed payment webhook processed once, and a shipping API response validated with a size limit and resilience.
API6 Sensitive Business Flows: Identifying Sensitive Flows, Idempotency-Key and Flow-Level Limits
Against API6 you first identify which business flows automation can damage, then give each flow its own rule. A filter that processes repeated POSTs once following the Idempotency-Key draft, a concurrent retry test, enforcing coupon and limited-item rules with database constraints and a conditional UPDATE, RFC 9470-style step-up, and a per-customer flow limit.
API5 BFLA: Automated Authorization Tests from the Endpoint Inventory and Separating Admin APIs
You close BFLA for good with tests that list the endpoints the application really exposes through EndpointDataSource and verify that each one carries an explicit authorization decision and has rows in the matrix. We separate the admin surface with a route group, a policy and its own port, show that RequireHost can be bypassed with the Host header and add a real port check, and handle per-method permissions and method override headers.
API4 Unrestricted Resource Consumption: Page Size, Query Complexity, Timeouts, Quotas and Costly External Calls
Against API4 you put an upper bound on every parameter, every endpoint and every external call that costs money, and guard it with tests. Starting from an unbounded list measured with 200,000 orders, we build page size, offset and sort allowlists, bulk and body limits, request timeouts with CancellationToken, and tenant- and plan-based report and SMS quotas with 429 and Retry-After.
API3 BOPLA: Property-Level Authorization, PATCH Requests and Response Shaping
You close BOPLA not with serializer settings but with a separate response type per role and a writable-field allowlist per role. Projections with Mapperly that break the build when a field is added, moving a different view to its own endpoint and policy, rejecting locked fields in JSON Merge Patch, and using the OpenAPI schema as a contract guarded by a test.
API2 Machine-to-Machine Authentication: API Key Design, HMAC-Signed Requests and Protecting Token Endpoints
A machine-to-machine API key is designed with a recognisable prefix, stored only as a hash, bound to a tenant and scopes, rotated with two active keys and revocable, and it never travels in the query string. We build a custom authentication handler, HMAC-signed requests with a timestamp and body hash, replay protection, and per-IP and per-account limits on endpoints such as password reset, all with tests.
Closing API1 BOLA Systematically: Tenant/Owner-Scoped Queries, Global Query Filters and Resource-Based Authorization
You close BOLA not by adding a Where to every endpoint but by making scope mandatory in the data access layer: tenant and owner filters with EF Core 10 named query filters, tests that confine unscoped queries to one marked class, relationship checks for sub-resources and bulk operations, the 403/404 split with a resource-based handler, and other-tenant scenarios generated automatically from the matrix.
The API Security Lab: A Multi-Tenant Orders API, an Authorization Matrix and a Security Test Harness
Most API security breaks on the question "whose data is this?", and you only catch it systematically with an authorization matrix kept apart from the code that states the expected status for each endpoint × actor × resource. We build a two-tenant, three-role Minimal API lab, run the matrix with an xUnit Theory, WebApplicationFactory and a test authentication handler, and see eight BOLA holes on the first run.
What Changed in Authentication and Identity from ASP.NET Core 6 to 11
The most important authentication changes from ASP.NET Core 6 to 10 don't break the build; they silently change behavior. We run the same code on .NET 6, 8 and 10 to show a single scheme becoming the default, SecurityToken turning into JsonWebToken, cookies returning 401 instead of 302 for APIs and the new metrics; then cover PAR in .NET 9, .NET 11's TimeProvider, passkey names and DBSC, and a migration checklist.