Securing Fintech APIs: A .NET Developer's Checklist

Security in a fintech API is not a feature you bolt on at the end, just before launch, when someone in compliance asks the uncomfortable question. It is a set...

Originally published onanselmfowel.com

Security in a fintech API is not a feature you bolt on at the end, just before launch, when someone in compliance asks the uncomfortable question. It is a set of assumptions you bake in from the very first endpoint you write. After years building payment APIs in .NET, this is the checklist I actually run through, presented roughly in the order things tend to go wrong in the real world.

Every value that touches money from outside is a claim to verify.
Every value that touches money from outside is a claim to verify.

Authentication and authorization are different problems

Authentication answers "who are you." Authorization answers "what are you allowed to do." Teams get the first right and the second catastrophically wrong with depressing regularity. The classic fintech breach is not a broken login screen. It is an authenticated, legitimate user accessing someone else's account by changing an ID in a URL or request body, because the endpoint checked that they were logged in but never checked that the resource was theirs.

// Authenticated is not the same as authorized.
[Authorize]
public async Task<IActionResult> GetAccount(string accountId)
{
    var account = await _accounts.GetAsync(accountId);

    // This line is the whole ballgame. Without it, any logged-in
    // user can read any account by guessing or enumerating ids.
    if (account.OwnerId != User.GetUserId())
        return Forbid();

    return Ok(account);
}

Every single resource access must verify ownership, not merely identity. I treat the absence of an ownership check on a resource endpoint as a release-blocking bug, no exceptions.

Validate everything at the edge

Treat every input as hostile, including inputs that arrive from your own internal services, because today's internal service is tomorrow's compromised foothold.

  • Bind to explicit DTOs, never directly to your entities. Over-posting, where a client sets a field you never meant to expose, is a real and common attack.
  • Validate types, ranges, and formats before any business logic runs.
  • Reject unexpected fields rather than silently ignoring them, so that a client sending something strange gets an error instead of a surprise.

Never trust the client on money

Amounts, fees, and exchange rates must be computed and verified on the server. If the client sends an amount, you validate it against limits and the actual balance; you never let the client tell you what something costs. This sounds almost insultingly obvious, and it remains one of the most common real-world flaws I find when reviewing other teams' systems.

Any value that touches money and arrives from outside your trust boundary is a claim to be verified, never a fact to be used. The client proposes; the server decides.

Secrets, transport, and logging

Keep secrets out of source control and out of config files; use a proper secrets manager and rotate them. Enforce TLS everywhere, including service-to-service traffic that "never leaves the network," because flat internal networks are exactly how a small breach becomes a total one.

Be deliberate about logging. A single log line that captures a full request body can leak card data or personal information straight into your observability stack, which instantly turns your logging system into a regulated data store with all the obligations that implies. Log identifiers and outcomes, never raw sensitive payloads.

Rate limiting and abuse

Payment endpoints are attractive targets for enumeration, credential stuffing, and brute force. Rate-limit per identity and per IP address, and treat repeated authorization failures not just as status codes to return but as a security signal worth alerting on. A spike in 403s from one source is often the first visible sign of an attack in progress.

Assume you will be audited

Build the audit trail before anyone asks for it, because retrofitting it after an incident is painful, expensive, and always incomplete. Who did what, when, from where, captured immutably and kept for as long as your regulators require. In a regulated business this is not optional polish; it is core functionality.

The pleasant surprise is that security and auditability are largely the same investment seen from two angles. The structured, immutable record that satisfies the auditor is the same record that lets you reconstruct an incident, and the access controls that stop a breach are the same ones that prove, after the fact, who could and could not have done a thing.

Conclusion: the boring boxes are the breaches

None of these items are exotic, and that is exactly the point. The breaches I have studied almost never come from a clever zero-day that no one could have anticipated. They come, overwhelmingly, from one of these ordinary boxes left unchecked: an ownership check that was skipped, a client-supplied amount that was trusted, a secret that was committed, a log line that leaked. Run the checklist. The discipline is the security.

Chat with us