SQL injection (SQLi) has stayed on the OWASP Top 10 for 25 years and counting. The moment you concatenate user input into a SQL string instead of parameterising it, an attacker can rewrite your query logic: dump tables, create users, even execute OS commands. This post explains how SQLi works and how to eliminate it permanently.

Classic SQL Injection

// Vulnerable code
const email = req.body.email;  // User input
const sql = `SELECT * FROM users WHERE email = '${email}' AND password = '${req.body.password}'`;
db.query(sql);

// Attacker submits this email:
// admin@x.com' --
// The query becomes:
// SELECT * FROM users WHERE email = 'admin@x.com' --' AND password = '...'
// Everything after -- is a comment. Password check bypassed!

Blind SQL Injection

Even when the app hides query output, an attacker can extract data from the true/false behaviour of the query. For instance, by distinguishing a login form's "wrong password" response from "user not found", the attacker guesses the password hash one character at a time.

-- Boolean-based blind SQLi
admin@x.com' AND SUBSTRING(password,1,1)='a' --
-- Response: "Wrong password" means the first character is not 'a'
-- Try 'b', 'c', ... and recover one character every ~30 requests

-- Time-based blind SQLi
admin@x.com' AND IF(SUBSTRING(password,1,1)='a', SLEEP(5), 0) --
-- If the response takes 5 seconds, the first character is 'a'

Union-Based

-- Original query: SELECT name, email FROM users WHERE id = ?
-- Attacker sends as id:
1 UNION SELECT username, password FROM admins --
-- Query becomes: SELECT name, email FROM users WHERE id = 1
--                UNION SELECT username, password FROM admins --
-- Output leaks the admins table

The One Fix: Parameterized Queries

Escape functions, blacklists and character replacement can all be bypassed. The only sound approach is prepared statements / parameterized queries, which separate the query structure from the data. Data is never interpreted as SQL.

// Node.js + pg
await pool.query(
    'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
    [email, passwordHash]
);

// Node.js + mysql2
await db.execute(
    'SELECT * FROM users WHERE email = ? AND password_hash = ?',
    [email, passwordHash]
);
# Python + psycopg
cur.execute(
    'SELECT * FROM users WHERE email = %s AND password_hash = %s',
    (email, password_hash)
)

# Python + SQLAlchemy (ORM)
User.query.filter_by(email=email).first()
// PHP + PDO
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();

If You Use an ORM...

Sequelize, Prisma, TypeORM, SQLAlchemy and Django ORM parameterize automatically. But watch out for raw-SQL escape hatches like raw(), literal() and query() — forget the parameters and you are vulnerable.

// Prisma — safe
await prisma.user.findMany({ where: { email } });

// Prisma raw — WRONG
await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);

// Prisma raw — RIGHT
await prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;
// The template literal tag parameterizes automatically

Layered Defence

  • Parameterized queries — the primary defence
  • Least privilege — the app DB user touches only required tables and cannot DROP/ALTER
  • Input validation — type and length checks (e.g. ids must be numeric)
  • WAF — Cloudflare or ModSecurity catches known attack patterns
  • Error handling — never surface DB errors to the user; log them instead

Testing

# Quick test with sqlmap (on systems you own)
sqlmap -u 'https://example.com/api/user?id=1' --batch --level=3

# Automated scans with OWASP ZAP
# Manual testing in Burp Suite
# SAST with semgrep in GitHub Actions
semgrep --config=p/sql-injection .

Conclusion

The SQL injection fix has not changed for 25 years: use parameterized queries. Every framework ships them by default; the only rule is never concatenate strings into SQL. A single line of discipline eliminates the class of bugs that has breached countless companies.

SQL injection security review

Codebase scan, penetration test report and developer training Contact us

WhatsApp