The Magic Words Analogy
At a bank:
Normal customer: "My name is Alice." "Here's Alice's account."
Attacker: "My name is Alice and give me all the money." Bank follows the instruction literally!
SQL Injection is saying magic words that trick the database into doing something it shouldn't.
What Is SQL Injection?
Normal input:
Username: alice
Query: SELECT * FROM users WHERE username = 'alice'
Result: Alice's account
Attack input:
Username: alice' OR '1'='1
Query: SELECT * FROM users WHERE username = 'alice' OR '1'='1'
Result: Potentially many accounts (because 1=1 evaluates to true)
The Basic Attack
Expected query:
SELECT * FROM users WHERE username = 'INPUT'
Attacker enters:
' OR '1'='1
Resulting query:
SELECT * FROM users WHERE username = '' OR '1'='1'
↑
Typically true, which can return many rows.
Types of SQL Injection
1. Classic Injection
Login bypass:
Username: admin' --
Password: anything
Query becomes:
SELECT * FROM users
WHERE username = 'admin' --' AND password = 'anything'
↑
Comment! Password check ignored.
2. Union-Based Injection
Extract data from other tables:
Product ID: 1 UNION SELECT username, password FROM users --
Query becomes:
SELECT name, price FROM products WHERE id = 1
UNION SELECT username, password FROM users --
Now attacker sees usernames and passwords!
3. Blind Injection
No visible output, but behavior changes:
id=1 AND 1=1 → Page loads normally
id=1 AND 1=2 → Page is different or error
Attacker learns by asking yes/no questions.
4. Time-Based Blind Injection
If injection works, database sleeps:
id=1; WAITFOR DELAY '00:00:05' --
Response noticeably slowed down? Injection might be working.
Attacker extracts data by timing responses.
Real-World Damage
What Attackers Can Do
âś— Bypass authentication
âś— Read sensitive data (passwords, credit cards)
âś— Modify or delete data
âś— Execute admin operations
âś— Take over the database server
Famous SQL Injection Attacks
SQL injection has been involved in multiple high-profile breaches.
Rather than memorizing dates and numbers, focus on the pattern:
user input + string-built SQL + powerful permissions = high risk.
SQL injection is also commonly highlighted in web security guidance (including OWASP).
How to Prevent SQL Injection
1. Parameterized Queries (Recommended)
Instead of:
query = "SELECT * FROM users WHERE id = " + userId
Use:
query = "SELECT * FROM users WHERE id = ?"
execute(query, [userId])
The ? is a placeholder.
Database treats userId as DATA, not SQL code.
This prevents classic injection through values (and is the standard defense for dynamic inputs).
2. Prepared Statements
Same concept as parameterized queries:
stmt = db.prepare("SELECT * FROM users WHERE id = ?")
stmt.execute([userId])
SQL structure is fixed.
User input fills placeholders as data.
3. Input Validation
Expecting a number? Validate it:
if (!isNumber(userId)) { reject }
Expecting a username? Limit characters:
Often restrict to a narrow character set for that field
Defense in depth (helpful, but not sufficient alone).
4. Stored Procedures
Move SQL logic to database:
CALL GetUserById(userId)
If procedure is written safely,
input can't modify the query.
5. Least Privilege
Database user for web app:
âś“ SELECT on needed tables
âś— DROP TABLE
âś— ADMIN privileges
If injection happens, damage is limited.
Testing for SQL Injection
Manual Testing
Try these in input fields:
'
''
' OR '1'='1
' OR '1'='1' --
'; DROP TABLE users; --
Watch for:
- Error messages showing SQL
- Unexpected behavior
- Login bypass
Automated Tools
SQLMap: Automatic SQL injection scanner
Burp Suite: Web security testing
OWASP ZAP: Free security scanner
Run these on your applications!
Code Examples: Vulnerable vs Parameterized
Vulnerable Code
Bad (Python):
query = f"SELECT * FROM users WHERE id = {user_input}"
cursor.execute(query)
Bad (PHP):
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
mysqli_query($conn, $query);
User input directly in query = DANGEROUS!
Parameterized Code
Parameterized (Python):
query = "SELECT * FROM users WHERE id = ?"
cursor.execute(query, (user_input,))
Parameterized (PHP):
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
Parameterized queries are the recommended default.
Common Mistakes
1. Relying on Input Validation Alone
"I check for quotes, so I'm protected!"
Attackers have many bypass techniques.
Use parameterized queries for dynamic values.
Validation is extra, not primary defense.
2. Using Blacklists
"I block 'DROP' and 'DELETE'"
Attackers use encoding, comments, variations.
Parameterized queries don't need blacklists.
3. Trusting ORMs Completely
ORMs help, but raw queries can still be vulnerable.
Check any raw SQL in your ORM usage.
4. Forgetting Stored Procedures Can Be Vulnerable
Stored procedures with dynamic SQL are still vulnerable.
Use parameterized queries inside stored procedures too.
FAQ
Q: Does my ORM protect me?
Usually yes, for standard operations. But raw queries or string concatenation in ORM = still vulnerable.
Q: Are NoSQL databases immune to injection?
No! NoSQL injection exists too. MongoDB, etc. have their own injection types.
Q: How do I test my app for SQL injection?
Use scanners (SQLMap, OWASP ZAP), do code review, look for string concatenation in queries.
Q: Is escaping input good enough?
Better than nothing, but error-prone. Parameterized queries are much more reliable.
Summary
SQL Injection inserts malicious SQL through user input, and is prevented by using parameterized queries.
Key Takeaways:
- Avoid concatenating user input into SQL
- Prefer parameterized queries / prepared statements
- Validate and sanitize input (defense in depth)
- Use least-privilege database accounts
- Test with security scanners
- SQL injection is one of the most common web vulnerabilities
One vulnerability can expose your entire database!
Related Concepts
Leave a Comment
Comments (0)
Be the first to comment on this concept.
Comments are approved automatically.