Bird
Raised Fist0
Flaskframework~10 mins

SQL injection prevention in Flask - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - SQL injection prevention
User Input Received
↓
Use Parameterized Query
↓
Database Query Executes
↓
Safe Data Returned
↓
Display Results to User
↓
END
The flow shows how user input is safely handled by using parameterized queries to prevent SQL injection.
Execution Sample
Flask
user_input = request.args.get('id')
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_input,))
result = cursor.fetchall()
This code safely queries the database using a parameterized query with user input.
Execution Table
StepActionInput/ConditionQuery Sent to DBResult
1Receive user inputuser_input = '1 OR 1=1'N/AN/A
2Prepare parameterized queryquery = "SELECT * FROM users WHERE id = %s"SELECT * FROM users WHERE id = %sN/A
3Execute query with parametercursor.execute(query, ('1 OR 1=1',))SELECT * FROM users WHERE id = '1 OR 1=1'No injection, treated as string
4Fetch resultscursor.fetchall()N/AReturns no user with id '1 OR 1=1' (likely none)
5Display resultsresultN/ASafe output shown to user
💡 Execution stops after safely fetching and displaying results without injection.
Variable Tracker
VariableStartAfter Step 1After Step 3Final
user_inputNone'1 OR 1=1''1 OR 1=1''1 OR 1=1'
queryNone"SELECT * FROM users WHERE id = %s""SELECT * FROM users WHERE id = %s""SELECT * FROM users WHERE id = %s"
resultNoneNoneNone[] or safe user data
Key Moments - 2 Insights
Why doesn't the input '1 OR 1=1' cause the query to return all users?
Because the input is passed as a parameter, the database treats it as a string value, not as SQL code, so no injection happens (see execution_table step 3).
What happens if we concatenate user input directly into the query string?
Direct concatenation would let the input be interpreted as SQL code, causing injection. Parameterized queries prevent this by separating code from data.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table at step 3, what does the database see as the query?
ASELECT * FROM users WHERE id = '1 OR 1=1'
BSELECT * FROM users WHERE id = %s
CSELECT * FROM users WHERE id = 1 OR 1=1
DSELECT * FROM users
💡 Hint
Check the 'Query Sent to DB' column in step 3 of the execution table.
At which step is the user input first used in the query execution?
AStep 2
BStep 3
CStep 1
DStep 4
💡 Hint
Look at the 'Action' column to see when cursor.execute is called.
If user_input was concatenated directly into the query string, what would change in the execution table?
AThe query would remain parameterized
BThe result would be empty always
CThe query sent to DB would include the raw input without quotes
DThe input would be ignored
💡 Hint
Think about how direct string concatenation affects the query in step 3.
Concept Snapshot
SQL Injection Prevention in Flask:
- Always use parameterized queries with placeholders like %s
- Pass user inputs as parameters, not by string concatenation
- This keeps user input as data, not executable code
- Prevents attackers from injecting harmful SQL
- Use cursor.execute(query, (user_input,)) pattern
- Always validate and sanitize inputs additionally
Full Transcript
This visual execution trace shows how SQL injection is prevented in Flask by using parameterized queries. User input is received as a string, then passed safely as a parameter to the database query. The database treats the input as data, not code, so malicious inputs like '1 OR 1=1' do not alter the query logic. The execution table walks through each step: receiving input, preparing the query, executing with parameters, fetching results, and displaying them safely. Variable tracking shows how user_input and query remain unchanged as code, and result holds safe data. Key moments clarify why parameterization stops injection and why direct concatenation is dangerous. The quiz tests understanding of query formation and execution steps. The snapshot summarizes best practices for preventing SQL injection in Flask applications.

Practice

(1/5)
1. What is the main purpose of using parameterized queries in Flask when working with databases?
easy
A. To speed up database queries by caching results
B. To prevent SQL injection attacks by separating code from data
C. To allow users to write their own SQL commands
D. To automatically create database tables

Solution

  1. Step 1: Understand SQL injection risk

    SQL injection happens when user input is treated as code, allowing attackers to change database commands.
  2. Step 2: Role of parameterized queries

    Parameterized queries keep user data separate from SQL code, stopping attackers from injecting harmful commands.
  3. Final Answer:

    To prevent SQL injection attacks by separating code from data -> Option B
  4. Quick Check:

    SQL injection prevention = parameterized queries [OK]
Hint: Remember: separate data from code to stop injection [OK]
Common Mistakes:
  • Thinking parameterized queries speed up queries
  • Believing users can safely write SQL commands
  • Confusing parameterized queries with table creation
2. Which of the following is the correct way to use parameterized queries with Flask's database cursor?
easy
A. cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
B. cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
C. cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
D. cursor.execute("SELECT * FROM users WHERE id = :id", user_id)

Solution

  1. Step 1: Identify correct placeholder syntax

    In Flask with many DB adapters like psycopg2, %s is used as placeholder for parameters.
  2. Step 2: Check parameter passing format

    Parameters must be passed as a tuple, e.g., (user_id,). cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) uses %s and tuple correctly.
  3. Final Answer:

    cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) -> Option C
  4. Quick Check:

    Use %s with tuple for parameters [OK]
Hint: Use %s and tuple for parameters in execute() [OK]
Common Mistakes:
  • Using f-strings directly with user input
  • Using ? placeholder which is for SQLite, not psycopg2
  • Passing parameters incorrectly without tuple
3. Given this Flask code snippet, what will be the output if user_id = "1 OR 1=1" and parameterized queries are used correctly?
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
results = cursor.fetchall()
print(results)
medium
A. Only rows where id equals the string '1 OR 1=1' will be returned
B. All rows from users table will be returned
C. Syntax error due to SQL injection
D. No rows will be returned because of wrong query

Solution

  1. Step 1: Understand parameterized query effect

    Parameterized queries treat user input as data, not code, so "1 OR 1=1" is a string value, not SQL logic.
  2. Step 2: Result of query with injected string

    The query looks for rows where id equals the string "1 OR 1=1", which likely matches no rows or only exact matches.
  3. Final Answer:

    Only rows where id equals the string '1 OR 1=1' will be returned -> Option A
  4. Quick Check:

    Parameterized input treated as data = Only rows where id equals the string '1 OR 1=1' will be returned [OK]
Hint: Parameterized input is data, not code, so no injection [OK]
Common Mistakes:
  • Assuming injection runs and returns all rows
  • Expecting syntax error from parameterized query
  • Thinking query fails due to input format
4. Identify the error in this Flask code that tries to prevent SQL injection:
user_id = request.args.get('id')
cursor.execute("SELECT * FROM users WHERE id = %s" % user_id)
results = cursor.fetchall()
medium
A. Using wrong placeholder %s instead of ?
B. Missing parentheses in fetchall()
C. Not converting user_id to integer
D. Using string formatting instead of parameterized query

Solution

  1. Step 1: Check how query is constructed

    The code uses string formatting (% operator) to insert user_id directly into the query string.
  2. Step 2: Why this is wrong for injection prevention

    Direct string formatting allows malicious input to change SQL code, causing SQL injection risk.
  3. Final Answer:

    Using string formatting instead of parameterized query -> Option D
  4. Quick Check:

    Use parameterized queries, not string formatting [OK]
Hint: Never build queries with string formatting; use parameters [OK]
Common Mistakes:
  • Thinking fetchall() needs parentheses fix
  • Believing user_id must be int for injection safety
  • Confusing %s and ? placeholders
5. You want to safely insert multiple user records into a database using Flask and prevent SQL injection. Which approach correctly combines parameterized queries with batch insertion?
users = [("alice", 25), ("bob", 30)]
cursor.executemany(??? , users)
What should replace ????
hard
A. "INSERT INTO users (name, age) VALUES (%s, %s)"
B. "INSERT INTO users (name, age) VALUES ('%s', '%s')"
C. "INSERT INTO users (name, age) VALUES (?, ?)"
D. "INSERT INTO users (name, age) VALUES (:name, :age)"

Solution

  1. Step 1: Identify correct placeholder syntax for batch insert

    For executemany with psycopg2 or similar, %s placeholders are used without quotes.
  2. Step 2: Check placeholder usage in options

    "INSERT INTO users (name, age) VALUES (%s, %s)" uses %s placeholders correctly; "INSERT INTO users (name, age) VALUES ('%s', '%s')" wrongly adds quotes, "INSERT INTO users (name, age) VALUES (?, ?)" uses ? (SQLite style), "INSERT INTO users (name, age) VALUES (:name, :age)" uses named placeholders which need dicts.
  3. Final Answer:

    "INSERT INTO users (name, age) VALUES (%s, %s)" -> Option A
  4. Quick Check:

    Use %s placeholders without quotes for executemany [OK]
Hint: Use %s placeholders without quotes for batch inserts [OK]
Common Mistakes:
  • Adding quotes around %s placeholders
  • Using ? placeholders with psycopg2
  • Using named placeholders without dict parameters
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard