Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Web Application Security: The Practices That Actually Prevent Incidents

Sean

Platform Writer

Sep 02, 2026
9 min read

Most web application security checklists are unordered, which makes them nearly useless — they put security headers next to authorization in a flat list, as though a missing header and a broken permission check were comparable risks. They are not.

Web Application Security: The Practices That Actually Prevent Incidents

Breach data has been reasonably consistent for years about what actually causes incidents in web applications: broken access control, credentials in the wrong place, unpatched dependencies, and injection. Security headers are worth setting and have prevented far fewer incidents than any of those. This list is ordered by that reality.

Table of contents

1. Authorization, checked server-side, on every request

Broken access control has sat at or near the top of application vulnerability rankings for years, and it is the least glamorous item on any list. The bug is almost always the same: the application checks who you are and forgets to check whether this particular record is yours.

The canonical version — an endpoint like /api/invoices/1043 that verifies you are logged in, fetches invoice 1043, and returns it, without ever asking whether invoice 1043 belongs to you. Change the number and read someone else’s data. This is trivially discoverable and it is still shipping in new applications every week.

What prevents it:

  • Deny by default. Every endpoint requires an explicit authorization decision; a new route with no decision is inaccessible rather than open.
  • Scope queries by owner in the query itself — WHERE id = ? AND account_id = ? — rather than fetching and then checking. The database enforces it and there is no branch to forget.
  • Never trust an identifier from the client to establish ownership. The user id comes from the session, always.
  • Test it. A test that logs in as user A and requests user B’s resource, asserting a 404 or 403, is worth more than most of a security budget.

Hiding a button in the UI is not authorization. The endpoint is public regardless of what the interface shows.

2. Secrets that are never in the code

Credentials committed to repositories are a leading cause of compromise, and the mechanism is well understood: automated scanners watch public repository feeds and test discovered keys within minutes. Not days — minutes.

The rules are short and absolute. No credential in source, ever, including in a config file that is gitignored, because gitignore protects you until the day someone adds it with -f. Everything comes from the environment at runtime.

Two things people get wrong beyond the obvious:

  • Git history. Removing a secret in a new commit does not remove it. It is in the history, and the history is what gets scanned. A leaked credential must be rotated, not deleted — treat any exposure as a compromise regardless of how quickly you noticed.
  • Client-side bundles. An API key in frontend JavaScript is public no matter what your build tool calls it. Every key that must be secret has to be used from a server.

Add secret scanning to continuous integration so a commit containing a credential fails the build. It is a small amount of configuration and it catches the mistake before it reaches a place where it matters.

And scope the credentials you do issue. A key that can only read one bucket is a much smaller incident than one that can do anything.

3. Dependencies, updated on a schedule you keep

A modern application is mostly other people’s code. The vulnerabilities in that code are public, indexed, and trivially matched against your published version numbers by anyone scanning.

This is not primarily a tooling problem — every ecosystem has an audit command and every platform offers automated dependency pull requests. It is a process problem: the alerts arrive, nobody owns them, and the backlog becomes noise that gets ignored, at which point the tooling is worse than useless because it provides false assurance.

What works:

  • A named owner and a recurring slot — an hour a week is enough for most codebases.
  • Automated pull requests for patch and minor updates, merged on green tests. Reserve human judgement for major versions.
  • A lockfile committed, so what you tested is what you deploy.
  • Fewer dependencies. The most reliable way to reduce this surface is to not add the package that saves you nine lines.

Prioritise by exploitability rather than by severity score. A critical vulnerability in a code path you do not call is less urgent than a moderate one in your request handler, and treating the numbers as the priority order guarantees you spend the hour on the wrong thing.

4. Injection, prevented structurally

SQL injection is decades old and still appears, because the fix is easy and the mistake is easier. The rule has not changed: parameterised queries, always, with no exceptions for internal tools or admin pages.

String concatenation into SQL is the vulnerability. It does not matter that the input came from a dropdown, an internal user, or another one of your own services. Use placeholders and let the driver handle it — the performance is the same and the class of bug disappears.

The same principle covers the neighbouring cases:

  • Command injection. Do not build shell strings from input. Use the argument-array form of your process API so there is no shell to inject into.
  • Cross-site scripting. Contextual output encoding, and a template engine that escapes by default. Every framework has an escape hatch for raw HTML; every use of it needs justifying.
  • Path traversal. Never join user input onto a filesystem path. Resolve the result and verify it is still inside the intended directory.
  • Server-side request forgery. If your application fetches URLs supplied by users, allowlist the destinations. Otherwise it will be pointed at your internal network.

Validate input at the boundary against a schema — types, lengths, allowed values. It catches a category of bugs beyond security and makes the rest of the code simpler to reason about.

5. Everything else, in proportion

These matter and belong on the list. They belong below the four above, and putting them first is how checklists mislead people.

  • HTTPS everywhere, with HSTS. Certificates are free and automatic; there is no remaining excuse for plaintext. HSTS closes the first-request downgrade window.
  • Sensible session handling. Cookies marked HttpOnly, Secure and SameSite. Session identifier rotated on login. Server-side invalidation on logout that actually invalidates.
  • Rate limiting on authentication. Per-account and per-address, with a delay rather than a hard block, so credential stuffing is expensive without letting an attacker lock out real users.
  • Security headers. A content security policy is genuinely valuable as defence in depth against cross-site scripting. The rest are cheap and marginal — set them, but do not mistake an A grade on a header scanner for a secure application.
  • Logging you can investigate with. Authentication events, authorization failures, and administrative actions, retained long enough to answer questions about last month. Most breaches are discovered late because nothing recorded the early signal.
  • Backups you have restored. Ransomware turns a backup strategy into the only thing that matters, and an untested backup is a belief rather than a plan.

If you did the first four properly and none of these, you would be in better shape than an application that did these and skipped authorization. That is the actual ranking, and it is not how most checklists are written.

How this fits the rest of the stack

Several items above are hosting decisions rather than code decisions — where secrets live, whether HTTPS is automatic, whether the database is reachable from the internet, whether logs exist and are searchable. Those belong in the plan before the first deploy, and the RunxBuild hosting calculator covers what the resulting stack costs. On RunxBuild, environment variables are injected at runtime rather than committed, certificates are issued and renewed as part of the deploy, managed databases sit behind private networking with configurable connection limits, and build and runtime logs are in the same place.

Useful related references:

FAQ

What is the most important web application security practice?

Server-side authorization checked on every request. Broken access control is consistently the most common serious application vulnerability, and it is usually the same bug: the application verifies who you are but not whether the specific record you asked for is yours.

Where should API keys and secrets be stored?

In environment variables injected at runtime, never in source code and never in a client-side bundle. A key in frontend JavaScript is public regardless of your build configuration. If a secret is ever committed, rotate it — removing it in a later commit does not remove it from the history.

How often should I update dependencies?

On a recurring schedule with a named owner — weekly works for most codebases. Automate patch and minor updates through pull requests merged on green tests, and reserve human review for major versions. Prioritise by whether you actually call the vulnerable code path, not by severity score alone.

Are security headers enough to secure a web application?

No. They are cheap, worth setting, and defensive in depth — a content security policy in particular. But they prevent far fewer real incidents than authorization, secrets handling, dependency updates and injection prevention. A perfect header scan on an application with broken access control is still a breach waiting to happen.

How do I prevent SQL injection?

Use parameterised queries with placeholders everywhere, with no exceptions for internal tools or admin pages. The vulnerability is string concatenation into SQL, and it does not matter whether the input came from a user, a dropdown, or another one of your own services.

#web application security best practices#authentication#authorization#secrets management#HTTPS