← cd ../cybersecurity

~/blog/cybersecurity/sql-injection-basics.mdx

SQL Injection, From First Principles

#web#appsec#databases

SQL injection remains one of the most common — and most preventable — classes of vulnerability. The root cause is simple: mixing untrusted data with code.

The vulnerable pattern

Consider a login query built by string concatenation:

# DON'T do this.
query = "SELECT * FROM users WHERE email = '" + email + "'"
cursor.execute(query)

If an attacker submits ' OR '1'='1 as the email, the query becomes:

SELECT * FROM users WHERE email = '' OR '1'='1'

The OR '1'='1' is always true, so the database happily returns every row.

The fix: parameterization

Let the driver separate code from data. The query text is fixed; values are sent separately and never interpreted as SQL:

# Safe: the value can never change the query's structure.
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (email,),
)

Parameterized queries aren't an "escaping" trick — they remove the decision of "is this code or data?" from the equation entirely.

Takeaways

  • Never build SQL by concatenating user input.
  • Prefer parameterized queries / prepared statements everywhere.
  • Treat ORMs as helpful, but understand what they emit.