SQL Injection: What It Is and How to Prevent It

SQL injection has been the #1 web vulnerability for decades. Yet it keeps appearing in production apps. Here's everything you need to know.

What Is SQL Injection?

It's when user input is concatenated directly into a SQL query, letting attackers rewrite the query.

Vulnerable Code

# NEVER DO THIS
username = request.form['username']
user = db.execute(
    f"SELECT * FROM users WHERE username='{username}'"
).fetchone()

If the attacker enters ' OR '1'='1, the query becomes:

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

This returns every user. The attacker is now logged in.

More Dangerous Payloads

-- Drop a table:
username: '; DROP TABLE users; --

-- Dump all passwords:
username: ' UNION SELECT email, password, null FROM users --

-- Read files (MySQL):
username: ' UNION SELECT load_file('/etc/passwd'), null, null --

The Fix: Parameterised Queries

Always pass user data as separate parameters — never concatenate:

# SAFE — always use this pattern
username = request.form['username']
user = db.execute(
    "SELECT * FROM users WHERE username=?",
    (username,)           # ← the DB driver handles escaping
).fetchone()

The ? is a placeholder. The database driver escapes the value before substituting it — so ' OR '1'='1 is treated as a literal string, not SQL syntax.

ORM Safety

ORMs like SQLAlchemy use parameterised queries by default:

user = User.query.filter_by(username=username).first()  # safe

But raw SQL through an ORM can still be vulnerable:

# DANGEROUS even inside an ORM
db.session.execute(f"SELECT * FROM users WHERE username='{username}'")

# SAFE
db.session.execute(
    "SELECT * FROM users WHERE username=:name",
    {"name": username}
)

Finding Injection Vulnerabilities

# sqlmap — automated detection
pip install sqlmap
sqlmap -u "https://example.com/login" --data "username=test&password=test"

Other Mitigations

  • Least Privilege: your DB user shouldn't have DROP or FILE permissions
  • WAF: a Web Application Firewall can block known payloads
  • Input Validation: validate types and lengths before queries
  • Error Handling: never expose raw DB errors to users

Parameterised queries solve 99% of SQL injection. There's no excuse not to use them.