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:
curl "http://10.10.10.20/item?id=1", a normal request.curl "http://10.10.10.20/item?id=1'", break it with a quote, read the error.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.