Cybersecurity Essentials for Modern Web Applications
Most web applications are not compromised by anything sophisticated. They are compromised through an out-of-date dependency, a password that was reused, or a permission that was checked in the interface but not on the server. The essentials below are unglamorous and they prevent the overwhelming majority of real incidents.
Validate on the server, always
Client-side validation is a convenience for users. It is not a security control, because anything running in the browser can be bypassed by anyone who wants to. Every rule that matters has to be enforced again on the server.
The same applies to authorisation, and this is the bug we find most often. Hiding an admin button from a non-admin user is not access control; the endpoint behind it still has to check who is calling. "Can this specific user perform this specific action on this specific record?" needs answering on every request, not once at login.
The injection classes, and what actually fixes them
- SQL injection: parameterised queries or a query builder that uses them. String concatenation into SQL is the whole problem, and it has a complete, boring fix.
- Cross-site scripting: escape on output, contextually. Modern frameworks do this by default — the danger is the escape hatch, the "render this as raw HTML" call. Treat every use of it as something requiring justification.
- Cross-site request forgery: anti-CSRF tokens on state-changing requests, plus
SameSitecookies. - Insecure deserialisation and file uploads: never trust a filename or a MIME type the client supplied, store uploads outside the web root, and verify the file is what it claims to be.
Authentication, done properly and not from scratch
Passwords hashed with bcrypt or Argon2 — never MD5, never SHA-1, never encrypted rather than hashed. Rate limiting and lockout on login. Multi-factor authentication for anything administrative. Session tokens that rotate on login and are invalidated on logout.
The broader principle: authentication is a solved problem with well-tested implementations, and writing your own is a way of introducing bugs that other people have already fixed. Use the framework's, or a reputable provider's.
Dependencies are where most breaches actually start
The average web application is mostly other people's code. A published vulnerability in a popular package is a public announcement to attackers, and automated scanning for unpatched sites begins immediately.
What this needs is a routine, not a project: know what you depend on, run automated vulnerability scanning in your pipeline, update on a schedule rather than when something breaks, and remove packages you no longer use. An abandoned dependency nobody has updated in three years is a liability sitting in your build. This is a large part of what a maintenance plan exists to handle, because it is exactly the work that gets postponed indefinitely otherwise.
Secrets, and where they must not be
API keys, database passwords and tokens belong in environment variables or a secrets manager — not in source control, not in a config file that ships with the repository, not in client-side JavaScript. If a secret has ever been committed, rotate it; the history is still there.
Transport and headers
HTTPS everywhere, with HTTP redirected rather than merely supported. Then a small set of headers that cost nothing to add: Strict-Transport-Security, X-Content-Type-Options: nosniff, a sensible Referrer-Policy, and a Content Security Policy if you can manage the effort — CSP is the most effective of these and also the most work, because it requires knowing what your pages legitimately load.
Assume it will happen anyway
Security is about reducing likelihood and limiting damage, not achieving certainty. So: back up daily, store backups somewhere the application cannot reach, and — the part almost everyone skips — restore one occasionally to confirm it works. A backup nobody has ever restored is a hope, not a control.
Log enough to reconstruct what happened. Know in advance who makes decisions during an incident, how you would take the site offline, and what your obligations are if personal data is involved. Deciding that while an incident is in progress is how small problems become expensive ones.
The short list
- Validate and authorise on the server, every request.
- Parameterised queries, contextual output escaping, CSRF tokens.
- Framework authentication, hashed passwords, MFA for admins.
- Automated dependency scanning and a real update schedule.
- Secrets out of the repository.
- HTTPS, security headers, and a CSP if you can.
- Tested backups and a written incident plan.
None of this is advanced. All of it is the difference between an application that gets attacked and one that gets breached.

