SQL Injection (SQLi) is one of the most dangerous web application vulnerabilities. It happens when untrusted input is inserted into a SQL query without proper safety checks. The result can be data leaks, authentication bypass, or even full database compromise.
What is SQL Injection?
SQL injection occurs when user input changes the structure of a SQL query. Instead of being treated as data, the input is interpreted as SQL code.
Why It’s Still a Big Risk
Many applications still build SQL strings manually. Even one unsafe query in a large system can open the door to attackers. SQL injection is common in:
- Legacy PHP or Java apps
- Internal dashboards with weak input validation
- APIs that trust JSON fields too much
- Admin panels and reporting tools
Basic Example
Vulnerable Code (PHP):
$username = $_GET['username'];$query = "SELECT * FROM users WHERE username = '$username'";Attack Input: ' OR '1'='1
Resulting Query:
SELECT * FROM users WHERE username = '' OR '1'='1'This makes the WHERE clause always true, returning all users.
More Vulnerable Patterns
1. String Concatenation in Login
$user = $_POST['user'];$pass = $_POST['pass'];$query = "SELECT * FROM users WHERE user='$user' AND pass='$pass'";2. Numeric Field Abuse
SELECT * FROM orders WHERE id = $idIf $id is not validated, input like 1 OR 1=1 can change the logic.
3. LIKE Queries
SELECT * FROM products WHERE name LIKE '%$search%'Unsafe input can break out of the string and inject SQL.
Types of SQL Injection
1. In-band SQLi
Error-based: Using database error messages to leak data.
' UNION SELECT 1, database(), version()--Union-based: Combining results from different queries.
' UNION SELECT username, password FROM users--2. Blind SQLi
Boolean-based: Inferring data from true/false responses.
' AND 1=1--' AND 1=2--Time-based: Inferring data from response delays.
' AND SLEEP(5)--3. Out-of-band SQLi
Data is extracted through external channels such as DNS or HTTP when direct output is blocked.
Exploitation Examples (High-Level)
1. Authentication Bypass
' OR '1'='1'--2. Extract Database Version
' UNION SELECT version(), null, null--3. List Databases
' UNION SELECT schema_name, null, null FROM information_schema.schemata--4. List Tables
' UNION SELECT table_name, null, null FROM information_schema.tables WHERE table_schema='appdb'--5. List Columns
' UNION SELECT column_name, null, null FROM information_schema.columns WHERE table_name='users'--6. Dump Credentials (Example)
' UNION SELECT username, password FROM users--7. Update or Delete Data
'; UPDATE users SET role='admin' WHERE user='attacker';--'; DELETE FROM logs;--These examples show how the query can be altered if input is not treated safely.
Safe Coding Examples
PHP (PDO Prepared Statements)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");$stmt->execute([$username]);Python (SQLite / DB-API)
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))Node.js (mysql2)
const [rows] = await conn.execute( "SELECT * FROM users WHERE email = ?", [email]);Java (JDBC)
PreparedStatement stmt = conn.prepareStatement( "SELECT * FROM users WHERE id = ?");stmt.setInt(1, userId);C# (ADO.NET)
using var cmd = new SqlCommand( "SELECT * FROM users WHERE username = @u", conn);cmd.Parameters.AddWithValue("@u", username);Example: Safe Search Endpoint (Python)
@app.get("/search")def search(q: str): sql = "SELECT id, name FROM products WHERE name LIKE ?" return db.execute(sql, ("%" + q + "%",)).fetchall()The query structure is fixed, and user input is treated as data only.
Example: Validation + Parameterization
if (!ctype_alnum($username)) { die("Invalid input");}$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");$stmt->execute([$username]);Validation reduces risk, but parameterization is the real protection.
Common Mistakes That Reintroduce SQLi
- Building SQL strings for dynamic sorting without a whitelist
- Using string concatenation for IN clauses
- Trusting values from cookies or JWT claims
- Running admin queries from user-controlled input
Secure Patterns for Dynamic Queries
Safe ORDER BY
$allowed = ['name', 'created_at'];$sort = in_array($sort, $allowed, true) ? $sort : 'name';$sql = "SELECT * FROM products ORDER BY $sort";Safe IN Clause
ids = [1, 2, 3]placeholders = ",".join(["?"] * len(ids))sql = f"SELECT * FROM orders WHERE id IN ({placeholders})"cursor.execute(sql, ids)Detection and Testing
- Static analysis to find risky query building
- Dynamic testing and fuzzing on input fields
- Runtime monitoring for SQL errors and unusual patterns
- Security reviews for database access layers
Prevention Strategies
- Always use prepared statements or ORM parameterization.
- Validate and normalize input.
- Apply least privilege for database accounts.
- Log and monitor suspicious database errors.
- Keep database and framework components updated.
Real-World Impact
SQL injection can cause:
- Exposure of sensitive data
- Authentication bypass
- Data loss or corruption
- Service disruption
Even a single vulnerable query can lead to serious incidents, so prevention must be systematic.
Learning Path
- Learn SQL basics and query logic.
- Practice in safe labs and training platforms.
- Understand how different databases behave (MySQL, PostgreSQL, MSSQL, SQLite).
- Study parameterized queries in your language.
- Learn secure design patterns for dynamic queries.
Summary
SQL injection is preventable. Never concatenate untrusted input into SQL queries. Always use prepared statements, validate inputs, and enforce least privilege. A secure database layer is not optional in modern applications.
Simple Advice
Treat every input as malicious until proven otherwise. Parameterized queries and strict validation remove most SQLi risks.
X : http://x.com/cat0x01github : http://github.com/cat0x01