SQL injection (SQLi)
Read first: The OWASP Top 10
TL;DR
SQL injection happens when an app builds a database query by gluing untrusted input straight into the SQL, so your input becomes part of the command. The fix is old, boring and total: never build queries by string concatenation — use parameterised queries.
Only test systems you own or are authorised to test. Everything here is for understanding and defending your own apps.
What it is
Most web apps keep their data in a database and ask for it with SQL. If the app takes something you typed — a username, a search box, an id in the URL — and drops it into a SQL statement as text, then your input stops being data and becomes part of the command. That is the whole bug.
How it works
Picture a login that builds its query by pasting input straight in:
SELECT * FROM users WHERE user = '<input>' AND pass = '...';
If the input is not kept separate from the query, a value containing a quote can close the string early and add logic the developer never intended, so the WHERE check stops meaning what it should. The classic teaching example is a value like ' OR '1'='1. The lesson is not the payload; it is that the input was allowed to change the shape of the query at all.
How to test for it
At the simplest level, testing for SQLi is about seeing whether input can influence the query:
- Put a single quote
'into a field and watch for a 500 or a broken page. An error mentioning SQL is a strong hint. - Compare an “always true” value against an “always false” one and see if the app behaves differently.
- Where nothing shows on screen (“blind” SQLi), testers look at side effects like timing. This is where in-scope tooling such as
sqlmapdoes the heavy lifting.
How to fix it
This is the important part, and it is genuinely simple:
- Use parameterised queries / prepared statements. Input is sent separately from the SQL, so it can never become part of the command.
- Prefer your framework’s ORM or query builder over hand-written SQL strings.
- Give the database account least privilege, so a mistake has a small blast radius.
A parameterised query (Python, psycopg style):
cur.execute("SELECT * FROM users WHERE user = %s", (username,))
Reference: OWASP: SQL Injection and the prevention cheat sheet.