Skip to content

step 24 / 32 · 6 min

The vulnerabilities you will actually meet

Security in a first job is rarely cryptography. It is a small number of recurring mistakes, and knowing them by name covers most of what goes wrong.

Injection

Building a query or command by concatenating input.

python
db.execute(f"SELECT * FROM users WHERE email = '{email}'")
# email = "' OR '1'='1"  ->  returns everyone

The fix is parameterisation, which sends the query and the values separately so the value can never be read as syntax:

python
db.execute("SELECT * FROM users WHERE email = ?", (email,))

Escaping by hand is the wrong fix: it depends on getting every case right, forever. The same principle applies to shell commands and to any interpreter.

Cross site scripting

Rendering user input as HTML, so their script runs in another user's browser with that user's session.

Modern templates escape by default, which is why the vulnerability now usually appears where someone deliberately bypassed it: dangerouslySetInnerHTML, v-html, | safe. Those names are warnings.

Broken access control

The most common serious flaw, and the least dramatic.

code
GET /api/orders/1234     # my order
GET /api/orders/1235     # somebody else's, and the server returns it

The interface never offered that link, so nobody tested it. Every request must check that this user may see this record, on the server, every time.

Authentication mistakes

MistakeInstead
Storing passwords, or hashing with SHA-256bcrypt, scrypt or argon2
No rate limit on loginlimit by account and by IP
Session id in the URLin a cookie, HttpOnly and Secure
Telling them which field was wrong"email or password is incorrect"

That last row is deliberate: distinguishing them confirms to an attacker which email addresses are registered.

Secrets

Not in the repository, not in the image, not in logs. In environment variables or a secret manager, with scanning in the pipeline, because this is a mistake competent people make regularly.

A secret that was committed is compromised. Rotate it; rewriting history does not recall what was already read.

Dependencies

Most of your application is other people's code. A known vulnerability in a library is as exploitable as one in yours, and far easier to find at scale.

Run a scanner in CI, update regularly rather than in a panic, and pin versions so a build is reproducible.

The habits

Validate on the server, always. Least privilege everywhere. Fail closed, so an error denies rather than permits. Log the security relevant events, and never the secrets.