SQL injection

SQL injection is a code injection vulnerability in which attacker-controlled input is concatenated into a SQL statement and then interpreted as part of the query by the relational database engine. The database cannot distinguish the code the application authored from the data the attacker supplied, so the input can alter the query’s structure – adding predicates, closing the statement early, or appending entirely new ones. The result is a query the application never intended to issue.

SQL injection is the canonical injection flaw and the close sibling of cross-site scripting (XSS). Both exploit code that mixes untrusted data with an interpreter without adequate separation; the difference is the target interpreter, the database engine rather than the browser. It has appeared on every edition of the OWASP Top Ten and was the top entry for years, because it is easy to introduce, easy to exploit, and frequently devastating in impact.

How it works

The vulnerability follows from string-building. An application that assembles SQL by interpolating user input hands the attacker control over the query text. A login that builds its lookup like this:

SELECT id FROM users
WHERE username = '<username>' AND password = '<password>';

becomes, when <username> is the string ' OR '1'='1:

SELECT id FROM users
WHERE username = '' OR '1'='1' AND password = '<password>';

The injected ' OR '1'='1 turns the WHERE clause into a tautology, so the query returns a row regardless of the password. The application, expecting a single matched user, logs the attacker in – often as the first account in the table, frequently an administrator.

The same shape escalates. Where the database driver permits stacked queries, an attacker can append a second statement terminated with a semicolon, eg. '; DROP TABLE users; --, to destroy data or to call administrative commands that the application never intended to run.

Variants

Exploitation is conventionally classified by how the attacker observes the result, because that determines what can be extracted.

  • In-band. The response that carries the data is the same channel the application uses for normal output. UNION-based injection appends a UNION SELECT to fold rows from other tables into the legitimate result set, and error-based injection provokes the database into emitting the sought data inside an error message.
  • Inferential (blind). The query returns no data the attacker can read directly, but its behavior changes observably. Boolean-based injection asks a yes/no question – AND 1=1 versus AND 1=2 – and reads the answer from whether the page renders content. Time-based injection asks the question by timing a SLEEP or equivalent, inferring the answer from the response latency.
  • Out-of-band. Where in-band and inferential channels are unavailable, the attacker triggers a side-channel such as a DNS lookup or HTTP request from the database server to a host they control, exfiltrating data through the request itself.

The categories describe the exploitation path, not the vulnerability. The underlying defect is the same in every case: code and data share one stream.

Impact

Because the query runs with the permissions of the application’s database account, the impact is bounded only by that account’s reach. Typical consequences include bypassing authentication, exfiltrating sensitive data, tampering with or destroying records, and forging audit trails. Where the account is over-privileged or the engine exposes filesystem, shell, or network primitives – such as xp_cmdshell on SQL Server or LOAD_FILE on MySQL – SQL injection escalates to full server compromise and can be used as a pivot into the internal network. The breach is often silent: a read-only SELECT leaves no trace the application logs.

Defenses

The primary control is to keep code and data separate, so that input can never be parsed as SQL syntax.

  • Parameterized queries (prepared statements). The application sends the query with placeholders and supplies the values separately. The driver ensures the values are treated strictly as data, never as part of the statement. This is the standard remedy and is available in every mainstream language and database library.
  • Stored procedures with parameters. Where a stored procedure is written to accept parameters rather than concatenate them, it provides the same separation. A procedure that builds SQL internally by string concatenation is itself injectable.
  • Object-relational mappers. Most ORMs generate parameterized queries by default and are safe on their typed query paths. Raw query escapes offered by the same libraries – and any hand-built SQL fed to them – reintroduce the risk and must be handled with the same care as hand-rolled statements.

Layered controls reduce residual risk and limit the blast radius when a vulnerability slips through.

  • Input validation rejects malformed data early and shrinks the surface, but it is a secondary measure. Validation alone cannot anticipate every encoding and dialect trick an attacker may use, and blacklist filtering is routinely evaded.
  • Least privilege on the database account – read-only where the code only reads, no DDL or administrative commands, no filesystem or shell access – caps the damage a successful injection can do. This is a practical instance of secure by design.
  • Security testing, penetration testing, and static analysis catch the defect before deployment. SAST tools in particular flag string-built SQL as a matter of course, since the pattern is well understood.

Warning

Blacklist-based input filtering – stripping or blocking known-bad SQL keywords – is a common and dangerous anti-pattern. Attackers evade it through encoding, casing, comments, and dialect-specific syntax, and it gives a false sense of security while leaving the underlying concatenation in place. Parameterization removes the defect; filtering only hides it.

See also

References