SQL Injection & NoSQL Injection

Why Injection Attacks Matter

Injection attacks have been the #1 threat on the OWASP Top 10 for over a decade โ€” and for good reason. A single unescaped user input can give an attacker full control over your database. They can read every user's password, delete entire tables, or even execute operating system commands on your server.

Modern APIs use multiple types of databases: PostgreSQL and MySQL (relational/SQL), MongoDB (NoSQL/document), and GraphQL APIs. Each has its own injection vectors, and each requires specific prevention techniques.

Why this matters for your career:

  • SQL Injection is the most tested vulnerability in every penetration exam (OSCP, GPEN)
  • Finding an SQLi in a bug bounty program typically pays $2,000 to $20,000+
  • Understanding injection attacks is fundamental to writing secure backend code
  • NoSQL injection is increasingly common with MongoDB's popularity

SQL vs NoSQL Injection: A Quick Comparison

| Feature | SQL Injection | NoSQL Injection | |:--------|:-------------|:----------------| | Target | Relational databases (PostgreSQL, MySQL, SQLite) | Document databases (MongoDB, CouchDB) | | Attack vector | String concatenation in SQL queries | Operator injection ($ne, $gt, $where) | | Exploit method | ' OR 1=1 --, UNION SELECT | {"$gt": ""}, {"$ne": ""} | | Defense | Parameterized queries, ORM | Input validation, type checking, strict schemas | | Prevalence | Declining (frameworks auto-protect) | Increasing (MongoDB popularity) |

๐Ÿ”ฅ Vibe Prompt

"Test a login API for SQLi. Show vulnerable vs parameterized query. Then test MongoDB NoSQLi."

import sqlite3, json

# VULNERABLE
conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE users (id INT, username TEXT, password TEXT)")
conn.execute("INSERT INTO users VALUES (1, 'admin', 'secret123')")

def vulnerable_login(username, password):
    # NEVER do this!
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    print(f"Query: {query}")
    return conn.execute(query).fetchone() is not None

# SQLi attack
print(f"SQLi: {vulnerable_login("admin'--", "anything")}")  # Bypasses auth!

# SAFE: parameterized
safe_query = "SELECT * FROM users WHERE username=? AND password=?"
print(f"Safe: {conn.execute(safe_query, ('admin'"'--", 'anything')).fetchone()}")  # Fails properly

# NoSQL injection (MongoDB)
# Vulnerable: db.users.find({username: req.body.username, password: req.body.password})
# Attack: {"username": "admin", "password": {"$ne": ""}} โ†’ matches!

# Safe fix:
# db.users.find({username: req.body.username, password: hash(req.body.password)})

Prevention

| Technique | How | |-----------|-----| | Parameterized Queries | WHERE id = %s | | ORM | SQLAlchemy, Prisma | | Input Validation | Reject special chars in usernames | | Least Privilege | DB user = SELECT only | | WAF | Block SQLi patterns |

Blind SQLi Detection

' OR 1=1 --        # Always true
' AND 1=2 --       # Always false
' AND SLEEP(5) --  # Time-based detection

Key Points

  • Understand the core concepts thoroughly
  • Practice with hands-on code examples
  • Apply knowledge to real-world problems
  • Review and reinforce through exercises

Further Learning

  • Official documentation
  • Open source projects on GitHub
  • Community forums and discussions
  • Related courses and tutorials

SQL Injection in APIs

SQL injection remains one of the most critical API vulnerabilities. Attackers inject SQL commands through input fields.

Detection

| Input | Expected Behavior | SQL Injection Test | |-------|------------------|-------------------| | 1 | Returns user 1 | 1 OR 1=1 โ€” returns all users | | ' | Error | Tests for unescaped quotes | | 1; DROP TABLE users-- | Error or table dropped | Tests for command chaining | | 1 UNION SELECT * FROM passwords-- | Extra data in response | Tests for UNION injection |

Blind SQL Injection

When no visible output, attackers use boolean or time-based techniques.

# Boolean-based: check if condition is true
curl "https://api.example.com/users/1 AND 1=1"  # Normal response
curl "https://api.example.com/users/1 AND 1=2"  # Different response

# Time-based: sleep if condition is true
curl "https://api.example.com/users/1; IF (1=1) WAITFOR DELAY '0:0:5'--"

NoSQL Injection

NoSQL databases (MongoDB) are also vulnerable to injection attacks.

MongoDB Injection

// โŒ Vulnerable: direct interpolation
app.get('/api/users', async (req, res) => {
  const { username } = req.query;
  // If username = { "$ne": "" }, this returns ALL users!
  const users = await db.collection('users').find({
    username: username
  }).toArray();
  res.json(users);
});

// โœ… Safe: validate input type
app.get('/api/users', async (req, res) => {
  const { username } = req.query;
  if (typeof username !== 'string') {
    return res.status(400).json({ error: 'Invalid input type' });
  }
  const users = await db.collection('users').find({
    username: { $eq: username }
  }).toArray();
  res.json(users);
});

NoSQL Injection Payloads

| Endpoint | Payload | Effect | |----------|---------|--------| | /api/users?username[$ne]= | {$ne: ""} | Returns all users | | /api/login | {"password": {"$gt": ""}} | Bypasses password check | | /api/search?q[$regex]=.* | {$regex: ".*"} | Returns all documents |

Prevention

| Database | Prevention Method | |----------|------------------| | SQL (PostgreSQL, MySQL) | Parameterized queries ($1, ? placeholders) | | SQL (any) | ORM (Prisma, TypeORM, SQLAlchemy) | | MongoDB | Use $eq operator, validate types | | MongoDB | Use Mongoose schemas with strict validation |

Parameterized Query Example

# Python + psycopg2 โ€” parameterized
import psycopg2

conn = psycopg2.connect("dbname=test")
cur = conn.cursor()

# โœ… Safe: %s placeholders
cur.execute(
    "SELECT * FROM users WHERE username = %s AND password_hash = %s",
    (username, password_hash)
)

# โŒ Vulnerable: string formatting
cur.execute(
    f"SELECT * FROM users WHERE username = '{username}'"
)

Summary

SQL and NoSQL injection attacks exploit unsanitized input. Parameterized queries, ORMs, and input type validation are the standard defenses.

Key takeaways:

  • SQL injection: inject SQL through input โ€” always use parameterized queries
  • Blind injection: infer data through boolean or timing responses โ€” never ignore response timing variations
  • NoSQL injection: MongoDB accepts operators ($ne, $gt, $regex) โ€” always restrict to $eq
  • Detection: test with ', OR 1=1, UNION SELECT โ€” if the response changes, you have a vulnerability
  • Parameterized queries: use %s, $1, ? placeholders or an ORM โ€” never use string formatting
  • Input type validation: reject objects/arrays when expecting strings โ€” critical for MongoDB
  • Mongoose/Prisma schemas: define expected types to prevent operator injection

What Is Next: Rate Limiting and JWT Session Security

Now that you understand how attackers inject malicious input into your database, the next chapter covers a different class of vulnerability โ€” rate limiting and session management. You will learn how attackers brute force passwords without restriction, how token theft works through XSS, and how to implement refresh token rotation for bulletproof session security.

Next Chapter: JWT and Session Attacks

The next chapter covers JWT attacks and session security.

Automated SQL Injection Testing

Using sqlmap for automated detection:

# Basic test
sqlmap -u "https://api.example.com/users?id=1"

# Test with POST data
sqlmap -u "https://api.example.com/login" --data="username=admin&password=test"

# Test headers
sqlmap -u "https://api.example.com/users" --headers="Authorization: Bearer *"

# Get database names
sqlmap -u "https://api.example.com/users?id=1" --dbs

# Get tables from a database
sqlmap -u "https://api.example.com/users?id=1" -D mydb --tables

You've completed this chapter! Next: JWT and session attacks.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!