Tech · 6 min read
A Backend Security Checklist for Working Engineers
The non-negotiable security practices every backend engineer should ship by default — auth, input validation, secrets, transport, dependencies, and the small habits that keep systems out of breach reports.
By Jarviix Engineering · Apr 19, 2026
Security in backend systems isn't usually defeated by exotic exploits. It's defeated by the same handful of mistakes — missing input validation, leaked secrets, outdated dependencies, weak auth — repeated across codebases for decades.
This post is a practical checklist of what to ship by default. None of it is exotic. All of it costs less to do upfront than to retrofit after an incident.
1. Authentication and authorization
The hardest area to get right and the most expensive to get wrong.
- Never roll your own auth. Use a battle-tested library or service (Auth0, Clerk, Keycloak, Devise, NextAuth). The amount of subtle logic — session lifecycle, token rotation, password reset, MFA — is genuinely too much to redo correctly.
- Hash passwords with a slow algorithm. Argon2id (preferred), bcrypt, or scrypt. Never SHA, MD5, or anything fast.
- Multi-factor authentication for privileged accounts. Admins, ops, anyone with prod access. TOTP or WebAuthn — not SMS if you can avoid it.
- Authorization checks at the resource level. Every endpoint, every resource, every read and every write. Don't trust the client's claim about which user they are; check on every action.
- Logout should be real. Invalidate the server-side session/refresh token. Don't rely on the client deleting the cookie.
For the deeper dive, see JWT explained — auth tokens are where most subtle auth bugs live.
2. Input validation
The classic OWASP categories — injection, XSS, deserialization — all reduce to "the application trusted input it shouldn't have".
- Validate at the boundary. Every external input gets validated against an explicit schema (Pydantic, Zod, JSON Schema, ProtoBuf). Reject anything that doesn't match.
- Use parameterized queries. Never string-concatenate user input into SQL. Use the parameterized API of your ORM or database driver. (One line of vigilance prevents 90% of SQL injection.)
- Escape output for context. HTML output → HTML escape. URL → URL encode. SQL → parameterize. JavaScript context inside HTML → JSON-encode and escape.
- Set strict CORS. Default to a deny list; explicitly allow only the origins you expect.
Access-Control-Allow-Origin: *with credentials is a vulnerability waiting to happen. - Limit upload size and types. A 10 GB POST will crash you. Validate MIME types, scan for malware on file uploads, store outside web root.
3. Transport security
- TLS everywhere. Including internal service-to-service traffic in modern environments. The only exception: localhost-only development.
- HSTS.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload— tells browsers to never connect over HTTP. - Modern cipher suites only. Disable TLS 1.0/1.1, weak ciphers, RC4, etc. Mozilla's SSL Configuration Generator is the easy starting point.
- Don't trust X-Forwarded-For blindly. Behind a load balancer, sanitize and validate. Otherwise clients can spoof their source IP for rate-limiting and audit logs.
4. Secrets management
The single highest-leverage area in security hygiene.
- No secrets in code. Not in config files, not in environment dumps, not in commit history. Even private repos get cloned, forked, or leaked.
- Use a secrets manager. AWS Secrets Manager, HashiCorp Vault, Doppler, 1Password Secrets Automation, or your platform's equivalent. Inject at runtime, never bake into images.
- Rotate aggressively. Database credentials, API keys, signing keys — automated rotation should be default. Quarterly minimum.
- Scan commits for secrets. Tools like
gitleaksor GitHub's secret scanning catch leaks at PR time. Once a secret is committed, treat it as compromised even if you delete the commit (history is forever). - Separate read and write credentials. Most app instances should have read-only DB access; only specific service roles get write/admin.
5. Dependencies
The supply chain attack surface most teams underestimate.
- Dependency scanning in CI.
npm audit,pip-audit,cargo audit, or hosted services like Snyk, Dependabot, Renovate. Block PRs that introduce known critical vulnerabilities. - Pin versions. Lockfiles, container image hashes. "Latest" in production is a foot-gun.
- Audit transitive dependencies. Most vulnerabilities live in the deep tree, not the top-level packages you chose.
- Minimize the dependency surface. Every dependency is something you implicitly trust. Question whether you really need that 12 KB package.
6. Logging and audit
You can't respond to what you didn't record.
- Log security-relevant events. Logins (success and failure), permission changes, role changes, password resets, MFA events, sensitive data access.
- Don't log secrets, passwords, or full tokens. Mask everything except the last few characters at most.
- Centralize logs. Logs on a single compromised host are useless after that host is compromised. Ship to a SIEM or central log store.
- Tamper-evident logs. For high-stakes systems, signed/append-only audit logs that an attacker can't quietly edit.
For the practical patterns, see microservices observability.
7. Rate limiting and abuse prevention
- Rate limit by IP and by user. IP catches anonymous abuse; user catches abusive accounts. (See designing rate limiters.)
- Lock out failed login attempts. After N failures, slow down. After N+M, lock out for a period. Notify the user.
- CAPTCHA on sensitive flows. Account creation, password reset. Reduce automated abuse cheaply.
- Honor
Retry-After. Don't be the API that rate-limits clients without telling them when to come back.
8. Data protection
- Encrypt at rest. Disk-level encryption is now table stakes. Most managed databases enable it by default.
- Encrypt sensitive fields at the application layer. SSN, payment data, anything regulated. Even if disk encryption is fine, app-layer encryption protects against DB dumps.
- Tokenize where possible. Card data, identifiers — replace with opaque tokens. The fewer copies of sensitive data you have, the less surface there is.
- Backups are part of the security boundary. Backups need the same encryption, access controls, and audit as production data.
- Delete what you don't need. GDPR and CCPA aside, less data = less liability.
9. Misconfiguration
The "boring" category that wins more breaches than the exciting ones.
- Disable default accounts. No
admin/admin. No vendor accounts left enabled. - Lock down admin interfaces. Database admin tools, dashboards, internal services — VPN-only, IP-restricted, MFA-required.
- Patch the OS and runtime. Hosted services largely handle this; for self-managed, automated patching is non-negotiable.
- Disable unused services and ports. If it's not running, it's not exploitable.
- Check headers.
X-Frame-Options,Content-Security-Policy,Referrer-Policy,X-Content-Type-Options: nosniff. Free defense. - Disable directory listings, default error pages with stack traces, debug endpoints in prod.
10. The human layer
Half of all breaches start with a successful phishing attempt or compromised credential.
- Hardware MFA for engineers with prod access. Phishing-resistant.
- Least-privilege access by default. Engineers don't need root in prod by default. Use just-in-time elevation.
- SSO with central identity provider. One place to revoke access when someone leaves.
- Onboard / offboard checklists. Access granted is logged. Access removed is logged. Quarterly audits.
A 30-minute starter audit
If this list feels like a lot, do the smallest version:
- Search the codebase for hardcoded secrets. Move them to a secrets manager. Rotate any that were exposed.
- Run a dependency scanner. Patch criticals.
- Confirm TLS is enforced everywhere (including internal traffic if applicable).
- Confirm rate limiting exists on auth endpoints.
- Confirm passwords are stored with Argon2/bcrypt/scrypt, not anything fast.
- Add structured audit logging for logins, role changes, and admin actions.
Most teams that do these six things move from "embarrassing" to "respectable" in less than a week.
What to read next
Security touches every other backend topic. JWT explained is the natural deep-dive on auth tokens; API versioning and idempotency cover the design hygiene that prevents another class of bugs; microservices observability is what lets you actually detect a problem when it happens.
Frequently asked questions
Where do I start if my app has no security review yet?
Auth, input validation, dependency scanning, and secrets management — in that order. Each takes a day or two and removes most of the practical attack surface.
Is OWASP Top 10 still relevant?
Yes. The specific vulnerabilities shift slightly each revision, but the patterns (injection, broken auth, misconfiguration) remain the most common causes of real breaches.
Do I need a WAF?
A WAF is a useful defense layer, especially against volumetric and signature-based attacks. It's not a substitute for fixing application-level vulnerabilities — it just buys time and reduces noise.
Read next
Apr 19, 2026 · 6 min read
JWT Explained: When to Use Them, When to Run, and What People Get Wrong
JSON Web Tokens are useful, popular, and routinely misused. A practical guide to what JWTs actually solve, where they fail, and the patterns that keep auth simple and safe.
Apr 19, 2026 · 6 min read
API Versioning Strategies: URL, Header, and the Trade-offs Nobody Tells You
URL versioning, header versioning, content negotiation, and 'no versioning at all' — what each costs, what each gets you, and how to pick a strategy you won't regret in three years.
Apr 19, 2026 · 6 min read
Caching Strategies for Backend Engineers: Cache-Aside, Write-Through, and the Rest
How to actually use a cache — when to use cache-aside, write-through, write-behind, refresh-ahead — and the failure modes (thundering herd, stampede, drift) that bite in production.