SQL Injection – Practical Guide & Cheat
Sheet
What is an SQL Injection attack?
An SQL Injection (SQLi) attack occurs when an application incorporates untrusted input
into an SQL query in a way that lets an attacker change the intended SQL command.
Attackers can read, modify, or delete database data — and in some cases escalate to remote
code execution or full system compromise.
Common SQLi Types & Short Examples
1. 1. Classic / Union-based
Goal: extract data by appending a UNION SELECT that matches the original query’s
column count/type.
Payload example: ' UNION SELECT username, password FROM users --
2. 2. Error-based
Goal: force the DB to return an error containing data (useful when results are shown).
Payload example (MSSQL-like): ' + convert(varchar, (select top 1 name from
sysobjects)) + '
3. 3. Boolean-based (blind)
Goal: infer data one bit/character at a time via true/false responses.
Payload example: ' AND (SELECT SUBSTR(password,1,1) FROM users WHERE
username='admin') = 'a' --
4. 4. Time-based (blind)
Goal: infer data by causing DB delays and measuring response times.
Payload example (MySQL): ' OR IF(SUBSTRING((SELECT password FROM users WHERE
username='admin'),1,1)='a', SLEEP(5), 0) --
5. 5. Second-order / Stored
Goal: malicious input is stored and later used in a query without re-sanitization (attack
triggers later).
Example: attacker stores '); DROP TABLE users; -- in a profile field that is later
concatenated into an admin report query.
6. 6. Out-of-band (OOB)
Goal: cause the DB to make an external DNS/HTTP request to attacker-controlled server
(useful when other channels are blocked).
Requires DB features that allow external interactions (DNS, HTTP functions).
How SQLi appears in source code (red flags)
Concatenating user input into SQL strings (e.g., "SELECT ...' + username + '...").
Using formatting functions with inputs: String.format, % substitution, f-strings with
user data.
Raw execute()/query() calls that build SQL from request params.
Displaying raw DB error messages to users (enables error-based SQLi).
Stored procedure or raw-query wrappers used with untrusted data.
Vulnerable vs Safe Examples
Vulnerable (Python, naive):
username = request.args.get('user')
query = "SELECT * FROM users WHERE username = '%s'" %
username
cursor.execute(query)
Safe (parameterized):
cursor.execute("SELECT * FROM users WHERE username = %s",
(username,))
# Or with an ORM: User.objects.filter(username=username)
Safe (Java JDBC prepared statement):
PreparedStatement ps = conn.prepareStatement("SELECT * FROM
users WHERE username = ?");
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
Typical Impacts
Data disclosure (read any table)
Data modification or deletion
Authentication bypass
Elevated privileges or command execution (via DB features)
Complete system compromise (pivot from DB to OS)
How to test / payloads to try (manual pentest basics)
Only test on systems you own or have explicit permission to test.
Basic tautology: ' OR '1'='1
UNION probe: ' UNION SELECT NULL-- (adjust column count)
Blind boolean: ' AND 1=1 -- (true) or ' AND 1=2 -- (false)
Time delay (MySQL): ' OR IF(1=1, SLEEP(5), 0) --
Extract single char (blind): ' AND (SELECT ASCII(SUBSTRING(password,1,1)) FROM
users WHERE username='admin') > 100 --
Detection techniques
Code review: search for string concatenation into DB calls and raw execute() with user
input.
Static analysis (SAST): scan for insecure DB API usage patterns.
Dynamic testing (DAST / pentest): inject payloads, use timing/boolean tests, automated
tools like SQLMap (with manual verification).
Logging & monitoring: detect anomalous query patterns, repeated failed queries, or
large UNION queries.
Prevention (definitive controls)
Use parameterized queries / prepared statements everywhere.
Use ORM query APIs and avoid raw SQL; if raw SQL is necessary, strictly parameterize.
Input validation (allow-list) for IDs, dates, emails — but do not rely on validation alone.
Least privilege DB accounts — application DB user only needs required CRUD rights.
Avoid exposing DB errors to end users; log them securely.
Disable dangerous DB features (e.g., xp_cmdshell, file writes) if not needed.
WAF / layered defenses as secondary protection (not a replacement).
SAST/DAST + manual code reviews in CI/CD.
Regular pentesting, including blind/time-based checks.
Quick checklist
All DB calls parameterized.
No string concatenation of SQL with user input.
Inputs validated where applicable.
App DB user has least privilege.
DB errors not leaked to users.
SAST/DAST and manual testing in place.