SQL injection (SQLi) occurs when untrusted input is interpreted as part of a SQL statement rather than as data. The main classes are:
### 1. In-band SQL injection
The attacker injects SQL and receives results through the same application channel.
- **Error-based:** Deliberately triggers database errors that reveal schema names, query structure, types, or data.
- **UNION-based:** Alters a `SELECT` query so additional rows from another query appear in the application response.
This class is often easiest to detect because results or detailed errors are visible directly.
### 2. Blind—or inferential—SQL injection
The application does not return database results or useful errors, so information is inferred from changes in behavior.
- **Boolean-based:** Sends conditions that are true or false and compares differences in content, status codes, redirects, or response length.
- **Time-based:** Uses database operations that conditionally delay execution; response timing reveals whether a condition was true.
Blind SQLi can be slower but remains serious even when error messages are suppressed.
### 3. Out-of-band SQL injection
The database is induced to communicate through another channel, such as a DNS or HTTP request. This depends on database features, privileges, and network egress. It is especially relevant when application responses provide no useful signal.
### 4. Stacked-query injection
If the driver or database accepts multiple statements in one call, injected input may terminate the intended statement and append another. Impact can extend beyond reading data to modification, account creation, or administrative operations, depending on privileges.
### 5. Second-order—or stored—SQL injection
Malicious input is stored safely at first, then later retrieved and concatenated into a different SQL statement. The vulnerable point is therefore not necessarily where the input originally entered the system. Batch jobs, reporting tools, administrative interfaces, and data migration code are common places to check.
### 6. Injection by query context
SQLi can appear in contexts other than quoted string values:
- Numeric values
- `ORDER BY` columns or sort directions
- Table or column identifiers
- `LIMIT`/pagination values
- `LIKE` patterns
- Dynamic filter expressions
- JSON, XML, or full-text query functions
- Stored procedures that construct dynamic SQL
Parameterization protects values, but identifiers and SQL keywords generally cannot be bound as parameters; those should be selected from strict allowlists.
## Root causes
Typical causes include:
- String concatenation or interpolation used to build SQL
- “Escaping” used instead of parameterized queries
- Unsafe dynamic SQL inside stored procedures
- ORM escape hatches such as raw-query methods
- Excessive database permissions
- Detailed database errors exposed to users
- Assuming validated or previously stored data is trustworthy
## Primary defenses
1. **Use prepared statements and bound parameters everywhere.**
2. **Allowlist dynamic identifiers and sort options.**
3. **Avoid dynamic SQL; if required, parameterize it internally.**
4. **Run the application under a least-privileged database account.**
5. **Return generic errors externally and log details securely.**
6. **Test all data paths, including background jobs and stored data.**
7. **Add automated SAST/DAST and code-review checks for raw SQL construction.**
8. **Treat a WAF as supplemental detection, not the primary fix.**
A concise message for developers is: **SQLi is prevented by keeping SQL syntax fixed and passing all user-controlled values separately as typed parameters.**