SQL Injection
What is SQL Injection?
Almost every web application keeps its data (users, balances, orders, messages) in a database, and talks to it using a language called SQL. SQL injection (SQLi) happens when an attacker's input becomes part of the SQL command itself, so the database runs instructions the developer never intended.
It is one of the oldest web vulnerabilities and it is still everywhere. In the OWASP Top 10, it sits inside the Injection category, and it has been behind some of the largest data breaches on record:
- Heartland Payment Systems (USA, 2008): attackers used SQL injection to plant malware that stole roughly 130 million card numbers.
- TalkTalk (UK, 2015): a SQL injection flaw exposed the personal details of about 157,000 customers, and the regulator fined the company £400,000.
Any application that takes input from a user (a login form, a search box, a transfer page, a URL like /products?id=7) and talks to a database is a possible target, whether it is a Lagos fintech, a London retailer or a government portal.
Legal note: Only practise these techniques on systems you own or have written permission to test, such as the lab below, TryHackMe or DVWA. Unauthorised access is a crime under laws such as Nigeria's Cybercrimes (Prohibition, Prevention, etc.) Act 2015, the UK Computer Misuse Act 1990 and the US Computer Fraud and Abuse Act.
How a Login Query Works
When you sign in to a banking app, the server has to check your username and password against the database. A careless developer writes it like this:
const query =
"SELECT id, username, password, role FROM users " +
"WHERE username = '" + username + "' " +
"AND password = '" + password + "'";
If you type amaka and Naija2024!, the server builds:
SELECT id, username, password, role FROM users
WHERE username = 'amaka' AND password = 'Naija2024!'
The database returns one row, and you are in. Everything works, until someone types something that is not a normal username.
The root cause is simple: the code mixes data and instructions in one string. The database cannot tell where the developer's code ends and the user's input begins.
The Attacks You Will Try in the Lab
1. Probing with a single quote
Typing just ' as the username breaks the string literal, and the database throws a syntax error. If you see an error (or the page behaves strangely), you have learnt that your input reaches the SQL parser. This is the standard first test.
2. Tautology: making the condition always true
Put this in the password field:
' OR '1'='1
The query becomes:
... WHERE username = 'admin' AND password = '' OR '1'='1'
'1'='1' is always true, so the WHERE clause matches every row and the app logs you in as the first user, usually the administrator.
Why not in the username field? In SQL,
ANDis evaluated beforeOR. Put the payload in the username and the password check still has to be true, so it fails. Understanding why a payload works is what separates a security professional from someone pasting strings.
3. Comment truncation
In SQL, -- (and # in MySQL) starts a comment: everything after it is ignored. Enter admin'-- as the username and the query becomes:
... WHERE username = 'admin'-- ' AND password = 'anything'
The password check has been commented out. You are logged in as admin without ever knowing the password.
4. UNION-based data extraction
UNION glues the results of a second query onto the first. If an attacker can append their own SELECT, they can read any table:
' UNION SELECT id, username, password, role FROM users--
The number of columns must match the original query, which is why attackers first probe with UNION SELECT 1,2-- and read the error. This technique turns a login bypass into a full data breach.
5. Stacked queries
A semicolon ends one statement and starts another: '; DROP TABLE users;--. Many modern database drivers refuse to run multiple statements in one call, but some stacks still allow it, and then an attacker can modify or delete data.
| Technique | Goal | Example |
|---|---|---|
| Error probe | Confirm the flaw exists | ' |
| Tautology | Bypass a condition | ' OR '1'='1 |
| Comment truncation | Skip part of the query | admin'-- |
| UNION extraction | Steal other tables | ' UNION SELECT ... |
| Stacked queries | Run extra commands | '; DROP TABLE users;-- |
There is also blind SQL injection, where the page shows no data or errors and the attacker infers answers from true/false behaviour or response timing. Tools like sqlmap automate this, and you will meet it in the ethical hacking module.
Hands-On Lab: Break Into NovaTrust Bank
The lab below simulates a bank login page with a deliberately vulnerable backend. It contains a small SQL engine, so your payloads succeed or fail for the same reasons they would against a real database.
- Click Run if the lab is not showing yet. Use the fullscreen button for more room.
- Press View Source Hint to see the vulnerable code.
- Watch the Query tab: your input appears in red inside the SQL statement as you type.
- Try the payloads from this lesson, then explore the Payloads tab. Read the Explain tab after every attempt.
- Find all 5 techniques to fill the progress bar.
- Flip the switch to Secure and replay every payload. Watch each one fail.
How to Fix It
Use parameterised queries (prepared statements)
This is the fix. The SQL text and the data are sent to the database separately, so input can never change the structure of the query:
const rows = await db.query(
"SELECT id, username, password_hash, role FROM users WHERE username = ?",
[username]
);
Even if the username is ' OR '1'='1, the database treats the whole thing as one literal string and looks for a user with that exact name.
Defence in depth
- ORMs and query builders (Prisma, Sequelize, SQLAlchemy, Eloquent) parameterise for you, but avoid their "raw query" escape hatches with string concatenation.
- Hash passwords with bcrypt or argon2. Never store them in plain text, and never compare them inside the SQL string.
- Least privilege: the app's database account should not be able to
DROPtables or read tables it does not need. - Hide database errors from users. Log them on the server and show a generic message.
- Validate input against an allow-list (a numeric id must be a number), as an extra layer, never as the only defence.
- A WAF is not a fix. Web application firewalls block common payloads but are routinely bypassed. Fix the code.
Notice what does not work: trying to strip out quotes or blacklist words like OR and UNION. Attackers find encodings and variations faster than defenders can extend the list.
Try it yourself
Key Takeaways
- SQL injection happens when user input is concatenated into a SQL string, letting attackers change what the query does.
- Core techniques: error probing, tautologies (OR '1'='1), comment truncation (--), UNION extraction and stacked queries.
- Understand why a payload works (for example, AND binds tighter than OR), not just which string to paste.
- The fix is parameterised queries. Add least-privilege database accounts, hashed passwords and generic error messages as extra layers.
- Blacklists, quote-stripping and WAFs are not fixes. Only test systems you own or are authorised to test.
Quick Quiz
1.What is the root cause of a SQL injection vulnerability?
2.Which payload in the password field makes the WHERE clause always true?
3.What does the payload admin'-- do in the username field?
4.Why does UNION-based injection require matching the number of columns?
5.Which is the most effective defence against SQL injection?
Ready to go further?
CareerEx gives you structured 12-week training, live classes every Saturday and Sunday, real tutor feedback, and a certificate. Join the next cohort.
Join CareerEx