Back to Research
March 19, 2026

How to Prevent SQL Injection, XSS, and CSRF in Modern Web Apps

How to Prevent SQL Injection, XSS, and CSRF in Modern Web Apps

Security is one of those things developers know is important…

But somehow, it always becomes:

“I’ll handle it later.”

And then “later” turns into:

  • A vulnerability report

  • A broken app

  • Or worst… compromised user data

I’ve made this mistake. More than once.

What’s frustrating is that most security issues are not even “advanced hacking.”

They’re basic mistakes.

So let’s talk about the three most common ones:

  • SQL Injection

  • XSS (Cross-Site Scripting)

  • CSRF (Cross-Site Request Forgery)

And more importantly:

👉 How to actually prevent them in real apps.

🧩 Why These Attacks Still Exist

Because modern frameworks make us feel safe.

  • ORMs hide SQL

  • React escapes HTML

  • Auth libraries handle sessions

And we start thinking:

“I don’t need to worry about security.”

That’s where things go wrong.

💣 SQL Injection: The “I Trusted User Input” Mistake

What it is

SQL Injection happens when user input is directly inserted into a query.

❌ Bad Example

const query = `SELECT * FROM users WHERE email = '${email}'`;
const result = await db.query(query);

If someone enters:

' OR 1=1 --

Your query becomes:

SELECT * FROM users WHERE email = '' OR 1=1 --

👉 Congrats. You just exposed your entire database.

😤 The frustrating part

You might think:

“I would never do this.”

But in complex apps, raw queries sneak in.

✅ How to Prevent SQL Injection

1. Use Parameterized Queries

const result = await db.query(
  "SELECT * FROM users WHERE email = ?",
  [email]
);

2. Use ORM Safely

With Prisma / Drizzle:

await db.user.findUnique({
  where: { email },
});

👉 No string concatenation = safe

3. Avoid Raw Queries (Unless Necessary)

If you must use them:

  • Always sanitize inputs

  • Use bindings

🧠 Real takeaway

Never trust user input. Ever.

🧨 XSS (Cross-Site Scripting): The “User Controls Your UI” Problem

What it is

XSS happens when attackers inject JavaScript into your app.

❌ Bad Example

<div dangerouslySetInnerHTML={{ __html: userInput }} />

If user input is:

<script>alert('Hacked')</script>

👉 That script runs in your app.

😤 The frustrating part

Sometimes you need to render HTML (e.g., rich text editors).

And that’s where things get risky.

✅ How to Prevent XSS

1. Avoid dangerouslySetInnerHTML

If possible:

👉 Don’t use it.

2. Sanitize HTML

import DOMPurify from "dompurify";

const clean = DOMPurify.sanitize(userInput);

3. Use React (Properly)

React escapes content by default:

<div>{userInput}</div>

👉 Safe

4. Set Security Headers

// example (Next.js headers)
{
  "Content-Security-Policy": "default-src 'self'; script-src 'self'"
}

🧠 Real takeaway

If users can inject HTML, they can inject JavaScript.

🔐 CSRF (Cross-Site Request Forgery): The “User Didn’t Mean That” Attack

What it is

CSRF tricks a user into making unintended requests.

Example

User is logged into your app.

They visit a malicious site that sends:

<form action="https://yourapp.com/api/delete-account" method="POST">
  <input type="submit" />
</form>

👉 If your app doesn’t protect against CSRF, the request succeeds.

😤 The frustrating part

You don’t see this happening.

It happens silently in the background.

✅ How to Prevent CSRF

1. Use CSRF Tokens

// backend
const token = generateCSRFToken();

// frontend
fetch("/api/action", {
  method: "POST",
  headers: {
    "X-CSRF-Token": token,
  },
});

2. Use SameSite Cookies

Set-Cookie: session=abc123; SameSite=Strict;

👉 Prevents cross-site requests

3. Use Auth Libraries

Libraries like NextAuth / Better Auth:

👉 Handle CSRF for you (mostly)

🧠 Real takeaway

If your app uses cookies for auth, you MUST think about CSRF.

⚖️ Modern Frameworks Help… But Don’t Save You

Let’s be honest:

  • ORMs reduce SQL injection risk

  • React reduces XSS risk

  • Auth libraries reduce CSRF risk

But none of them guarantee safety.

😤 The Dangerous Mindset

“The framework will handle it.”

That mindset creates vulnerabilities.

🧠 Practical Security Checklist

If you’re building a real app, do this:

✅ Database

  • Use parameterized queries

  • Avoid raw SQL

✅ Frontend

  • Never trust user input

  • Sanitize HTML

  • Avoid dangerous rendering

✅ Backend

  • Validate all inputs

  • Use schemas (Zod, etc.)

✅ Auth & Requests

  • Use CSRF tokens

  • Set secure cookies

  • Enable HTTPS

😤 The Truth Nobody Tells You

Here’s the uncomfortable truth:

Most security bugs are not complex.

They happen because:

  • You were in a hurry

  • You trusted input

  • You assumed something was safe

🧠 My Personal Lesson

After dealing with these issues:

  • I stopped trusting “default safety”

  • I started validating everything

  • I assume every input is malicious

Because honestly:

It’s easier to be paranoid than to fix a hacked system.

🧠 Final Thought

Security is not a feature.

It’s a mindset.

You don’t “add” it later.

You build with it from the beginning.

Thank you for reading. If you have any questions or feedback about this research, feel free to reach out.