SQL injection occurs when untrusted input is interpreted as part of a SQL command rather than as data. Developers should understand these broad classes:
### 1. In-band SQL injection
The attacker sends input and receives database results through the same application channel.
- **Error-based:** Deliberately triggers database errors that reveal schema, query, or data details.
- **UNION-based:** Alters a query so additional rows from another table appear in the normal response.
- **Authentication/logic manipulation:** Changes conditions—such as login or authorization checks—to produce an unintended true result.
### 2. Blind (inferential) SQL injection
The application does not directly expose query results, but its behavior lets an attacker infer information.
- **Boolean-based:** Different page content, status codes, or response behavior reveals whether a condition is true or false.
- **Time-based:** Conditional database delays reveal the truth of a condition through response timing.
### 3. Out-of-band SQL injection
The database is induced to send information through another channel, such as a network request. This is less common and depends on database features and outbound connectivity.
### 4. Stacked or piggy-backed queries
Input terminates the intended statement and adds another SQL statement. Whether this works depends on the database driver and whether multiple statements are allowed.
### 5. Second-order SQL injection
Malicious input is stored safely at first but later inserted unsafely into another SQL statement—for example, by a reporting job, administrative tool, or stored procedure. Validation only at initial entry does not prevent this.
### 6. Dynamic SQL in stored procedures
Stored procedures are not automatically safe. If they build SQL by concatenating arguments, they can be injectable just like application code.
## Injection contexts developers often miss
Injection is not limited to quoted string values. It can occur in:
- Numeric values
- `LIKE` patterns
- `IN` lists
- Table or column names
- `ORDER BY` fields and sort directions
- JSON/XML query functions
- Full-text or ORM “raw query” features
Parameterized queries generally protect **values**, but identifiers and SQL keywords cannot usually be bound as parameters. Those must be selected from strict allowlists.
## Primary defenses
1. **Use parameterized queries/prepared statements everywhere.**
2. **Never build SQL by concatenating or interpolating untrusted data.**
3. **Allowlist dynamic identifiers and sort options.**
4. **Avoid dynamic SQL inside stored procedures; parameterize it when unavoidable.**
5. **Use least-privileged database accounts** and separate read/write roles where practical.
6. **Return generic errors externally; log detailed errors securely.**
7. **Disable multi-statement execution and unnecessary database/network capabilities.**
8. **Test all query paths**, including background jobs, reports, exports, admin tools, and stored data reuse.
9. Treat input validation and web application firewalls as **additional layers**, not substitutes for parameterization.
The key briefing message is: **SQL injection is primarily a query-construction defect, not merely an input-validation defect. Keep code and data structurally separate.**