learn/phase-3/p3-w11/lesson 02
Milestone 11 · lesson 2

SQL Injection: Talking Straight to the Database

Hands-on. Understand how unsanitised input reaches a SQL query, and bypass a login with a classic payload.
Lab: UNION Dump

Confirm SQL injection, then use a UNION query to dump the users table.

What you'll learn

  • Explain what a SQL query is and how user input gets unsafely glued into one.
  • Recognise the tell-tale signs of a SQL injection point (errors, odd behaviour on a quote).
  • Use the classic authentication-bypass payload and understand exactly why it works.
  • Know the real fix, parameterised queries, and why input filtering alone is not enough.

SQL Injection: Talking Straight to the Database

Most web apps store their data, users, passwords, orders, in a database, and they ask for it using SQL (Structured Query Language). SQL injection is what happens when your input sneaks into one of those queries and changes what it means. It is one of the oldest bugs on the web, and still one of the most damaging.

First, what a query looks like

When you log in, the server runs something like this behind the scenes:

SELECT * FROM users WHERE username = 'alice' AND password = 'secret';

The app built that string by gluing your input into the middle of it:

"SELECT * FROM users WHERE username = '" + input_user + "' AND password = '" + input_pass + "';"

See the problem? Your input lands inside the quotes, as data. But what if you send input that breaks out of the quotes?

The classic login bypass

Enter this as the username:

' OR '1'='1

Now watch what the query becomes:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';

Your ' closed the username string early, and OR '1'='1' added a condition that is always true. The database happily returns rows, usually the first user in the table, which is often the admin. You're logged in without ever knowing a password. Your input stopped being data and became logic.

That is the entire heart of injection: data crossing the line into code.

Finding an injection point

You rarely see the query, so you probe. The number-one tell:

# a normal request
curl "http://10.10.10.20/item?id=1"

# add a single quote and watch for a database error
curl "http://10.10.10.20/item?id=1'"

If that quote produces a SQL error (or the page behaves strangely, blank, different results), your input is reaching the query unsanitised. Other quick tells: id=1 OR 1=1 returns more rows than id=1, and id=1 AND 1=2 returns fewer.

What an attacker does next

Once a parameter is injectable, the classic escalation is a UNION query that appends the attacker's own SELECT onto the app's, letting them read other tables:

id=1 UNION SELECT username, password FROM users

Now the page that was meant to show one product instead prints every username and password hash. From "log in as admin" to "dump the whole database" is a short step, which is why injection sits so high on the OWASP list.

Tools like sqlmap automate all of this, but you should understand the manual version first, otherwise the tool's output is just noise.

The real fix

You cannot fix injection by blocking quotes, attackers have endless encodings and tricks. The correct fix is a parameterised query (also called a prepared statement):

# vulnerable: input glued into the string
cursor.execute("SELECT * FROM users WHERE name = '" + name + "'")

# safe: input sent separately, never parsed as SQL
cursor.execute("SELECT * FROM users WHERE name = ?", (name,))

With the safe version, the database treats name as pure data, no matter what characters it contains. The line between data and code is enforced by the database itself.

Try it (terminal)

The lab beside this lesson has an injectable login. Warm up here first:

  1. curl "http://10.10.10.20/item?id=1" , a normal request.
  2. curl "http://10.10.10.20/item?id=1'" , break it with a quote, read the error.
  3. curl "http://10.10.10.20/item?id=1 OR 1=1" , make the condition always true.

Why this matters

SQL injection reaches the one place that holds everything: the database. A single injectable parameter can dump every account, forge a login, or in the worst cases run commands on the server. Understanding it, both the attack and the parameterised-query fix, is a rite of passage for anyone learning web security.

Check your understanding

4 questions

Type an answer and press Check. Grading is keyword-based and forgiving, so short answers are fine.

  1. 1

    A login runs SELECT * FROM users WHERE name='<input>' AND pass='<input>'. Write what you'd enter as the username to log in without knowing any password.

  2. 2

    You want to confirm a ?id= parameter is injectable. Write the single-character test that breaks the query's syntax, and what a positive result looks like.

  3. 3

    The parameter ?id=1 is injectable. Write a UNION payload that dumps the username and password columns from a users table.

  4. 4

    What is the correct, real-world fix for SQL injection?