# Injection and Parameterised Queries — DevSecOps

Source: https://www.skillbyai.com/en/devsecops/dso-injection

> Explain why string-built queries are injectable and fix them with parameterised queries, tracing the difference step by step.

## Data that becomes code

**Injection** happens when untrusted input is concatenated into something an interpreter parses: SQL, shell commands, LDAP filters or templates. The interpreter cannot tell where your code ends and the attacker's text begins. If a login query is built as `"... WHERE name = '" + name + "'"` and the attacker types `' OR '1'='1`, the condition becomes always true. The fix is to keep code and data in separate channels. With a **parameterised query** (prepared statement), the SQL text contains placeholders such as `?` and the driver sends the values separately, so they are always treated as data, never as SQL syntax. Escaping by hand is fragile; ORMs and query builders parameterise for you as long as you avoid their raw-string escape hatches. The same principle applies to shells: pass an argument list to `subprocess.run` instead of building a command string with `shell=True`.

## Tracing an injection, then the fix

Follow how the same malicious input behaves in a string-built query and in a parameterised one.

```python
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE users (name TEXT, role TEXT)")
db.executemany("INSERT INTO users VALUES (?, ?)", [("asha", "admin"), ("ravi", "user")])
evil = "x' OR '1'='1"
unsafe = f"SELECT name FROM users WHERE name = '{evil}'"
print("unsafe:", db.execute(unsafe).fetchall())
safe = db.execute("SELECT name FROM users WHERE name = ?", (evil,)).fetchall()
print("safe:", safe)
```

Output:

```
unsafe: [('asha',), ('ravi',)]
safe: []
```

- Line 2: An in-memory SQLite database is created, so the demo needs no server.
- Line 4: Two users are inserted. Even the setup uses placeholders, a good habit.
- Line 5: The attacker's input contains a quote that will close the string literal early.
- Line 6: The f-string pastes the input into the SQL text, producing WHERE name = 'x' OR '1'='1', which is true for every row.
- Line 7: SQLite parses the injected OR clause as code and returns all users.
- Line 8: Here the SQL text only has a placeholder. The whole input is bound as one string value.
- Line 9: No user is literally named x' OR '1'='1, so the safe query returns nothing.

## Filling a printed form

A bank form has a box labelled 'Name'. Whatever you write in the box stays a name; writing 'and also transfer ten lakh' in it does not become an instruction. A parameterised query is the printed form; string concatenation is letting the customer rewrite the form itself.

**Quiz:** Why does a parameterised query prevent SQL injection?

- [ ] It removes all quote characters from input
- [ ] It encrypts the query before sending it
- [x] The values are sent separately from the SQL text and are always treated as data
- [ ] It limits input length to 255 characters

*Answer:* The values are sent separately from the SQL text and are always treated as data. The query structure is fixed before values are bound, so input can never change the SQL syntax.
