What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →You don't need to be a security specialist to avoid the bugs attackers exploit most. A practical checklist covering injection, XSS, CSRF, access control, secrets, dependencies and headers.
Most web apps don't get breached through some brilliant zero-day. They get breached through the same handful of mistakes, over and over: a query built with string concatenation, an endpoint that forgets to check who owns a record, a secret sitting in a public repo. The good news is that these are all preventable with habits, not heroics.
Use this as a checklist before you ship, and again whenever you add a major feature. It lines up with the categories in the OWASP Top 10, which is worth reading in full once.
// Vulnerable
db.query(`SELECT * FROM users WHERE email = '${email}'`)
// Safe: parameterized
db.query('SELECT * FROM users WHERE email = $1', [email])
raw, unsafe, literal) are reviewed carefully.eval, or template engines without strict validation.XSS happens when user-supplied content runs as code in someone else's browser.
dangerouslySetInnerHTML, v-html or innerHTML with user content goes through a sanitizer like DOMPurify.Authentication answers "who are you?" Authorization answers "are you allowed to do this, to this record?" Forgetting the second one is extremely common.
// Vulnerable: any logged-in user can read any invoice by changing the ID
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
res.json(await Invoice.findByPk(req.params.id))
})
// Safe: scope the query to the current user
const invoice = await Invoice.findOne({ where: { id: req.params.id, userId: req.user.id } })
if (!invoice) return res.status(404).end()
HttpOnly, Secure and SameSite. (Sessions vs JWT, compared.)If you can, use a well-maintained auth library or provider instead of writing this yourself.
If you authenticate with cookies, another site can try to make the user's browser send requests to yours.
SameSite=Lax or Strict.Your app is mostly other people's code.
npm audit, pip-audit or equivalent runs in CI.Strict-Transport-Security (HSTS) is set.X-Content-Type-Options: nosniff is set.frame-ancestors (or X-Frame-Options) to prevent clickjacking.Referrer-Policy is set to something sensible, like strict-origin-when-cross-origin.Libraries like Helmet (Express) set most of these in one line.
Security isn't a phase at the end of a project. A few habits keep you ahead:
Broken access control, meaning users can reach data or actions they shouldn't, consistently ranks at the top. It's usually a missing ownership check on the server.
Frameworks prevent many issues by default (escaping output, parameterized queries, CSRF tokens), but they can't check your authorization logic or stop you from bypassing their protections.
Argon2id is the modern recommendation, with bcrypt and scrypt as solid alternatives. Use your language's well-maintained library rather than implementing anything yourself.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →