SkillByAIOpen interactive version →

Lesson 7 / 25

SQL Injection

Parameterised queries.

Separate code from data

SQL injection happens when user input is concatenated into a query, so input like ' OR '1'='1 changes the query's meaning, exposing or modifying data. The fix is parameterised queries (prepared statements) or a safe ORM API, where values are sent separately from the SQL text and are never interpreted as code. Identifiers such as column names for sorting cannot be parameters, so map them through an allow-list. Least-privilege database accounts limit the damage of any remaining flaw.

Keep data from becoming code

Injection happens when untrusted data is interpreted as part of a command, query or page.

Figure 3.1 — SQL injection, XSS and command injection.

Vulnerable and fixed queries

Python DB-API style.

# VULNERABLE: input becomes part of the SQL text
query = f"SELECT id, email FROM users WHERE email = '{email}'"
cursor.execute(query)

# FIXED: parameter placeholder; the driver sends the value separately
cursor.execute("SELECT id, email FROM users WHERE email = %s", (email,))

# Dynamic ORDER BY: allow-list the column name
SORTABLE = {"created": "created_at", "email": "email"}
column = SORTABLE.get(sort, "created_at")
cursor.execute(f"SELECT id, email FROM users ORDER BY {column} LIMIT %s", (limit,))

Escaping is not the fix

Manual escaping is easy to get wrong; parameterisation removes the problem by design.

Quick check: What is the primary defence against SQL injection?

  • Parameterised queries
  • Hiding error messages
  • Using POST requests
  • Client-side validation
Answer

Parameterised queries — Values never become SQL code.