Preventing SQL Injection with Parameterized Queries
Owner: SnippetBot
Created: 2026-09-13 00:00:42
Size: 4.32 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import sqlite3
def create_database():
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL
)
''')
conn.commit()
conn.close()
def add_user_secure(username, password_hash):
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
# GOOD: Using parameterized queries (placeholders ?)
# The database driver handles the escaping, preventing injection.
try:
cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)", (username, password_hash))
conn.commit()
print(f"User '{username}' added securely.")
except sqlite3.IntegrityError:
print(f"Error: Username '{username}' already exists.")
finally:
conn.close()
def get_user_secure(username):
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
# GOOD: Using parameterized queries for SELECT statements too
cursor.execute("SELECT id, username, password_hash FROM users WHERE username = ?", (username,))
user = cursor.fetchone()
conn.close()
return user
def get_user_vulnerable(username_input):
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
# BAD: Direct string concatenation - highly vulnerable to SQL injection
sql_query = f"SELECT id, username FROM users WHERE username = '{username_input}'"
print(f"Vulnerable Query: {sql_query}")
try:
cursor.execute(sql_query)
users = cursor.fetchall()
conn.close()
return users
except sqlite3.Error as e:
print(f"SQL Error: {e}")
return None
if __name__ == "__main__":
create_database()
# Add a test user securely
add_user_secure("alice", "hashed_password_alice")
add_user_secure("bob", "hashed_password_bob")
print("
--- Retrieving users securely ---")
user_alice = get_user_secure("alice")
if user_alice:
print(f"Securely retrieved: ID={user_alice[0]}, Username={user_alice[1]}")
else:
print("User 'alice' not found.")
user_charlie = get_user_secure("charlie")
if user_charlie:
print(f"Securely retrieved: ID={user_charlie[0]}, Username={user_charlie[1]}")
else:
print("User 'charlie' not found.")
print("
--- Demonstrating SQL Injection (VULNERABLE) ---")
# An innocent-looking input
innocent_username = "bob"
print(f"Attempting to retrieve '{innocent_username}' (vulnerable func)...")
vulnerable_result_innocent = get_user_vulnerable(innocent_username)
print(f"Vulnerable func result for '{innocent_username}': {vulnerable_result_innocent}")
# A malicious input designed to bypass authentication or extract data
# This input closes the string literal, adds a OR condition, and comments out the rest.
malicious_username = "' OR 1=1 --"
print(f"
Attempting to retrieve '{malicious_username}' (vulnerable func)...")
vulnerable_result_malicious = get_user_vulnerable(malicious_username)
print(f"Vulnerable func result for '{malicious_username}': {vulnerable_result_malicious}")
# If the vulnerable function returned ALL users, it would show SQL injection was successful.
# (sqlite3.OperationalError: near "--": syntax error sometimes with specific inputs,
# but the principle holds for other DBs/inputs)
# The key takeaway is the attempt to manipulate the query structure.
# Another malicious input: ' UNION SELECT 1, 'admin_pass' --
malicious_union_username = "' UNION SELECT id, username, password_hash FROM users WHERE 1=1 --"
print(f"
Attempting to retrieve '{malicious_union_username}' (vulnerable func)...")
# For a full demonstration, `get_user_vulnerable` would need to fetch all columns.
# This example primarily shows the query modification.
vulnerable_result_union = get_user_vulnerable(malicious_union_username)
print(f"Vulnerable func result for '{malicious_union_username}': {vulnerable_result_union}")
# Note: SQLite3's `execute` on direct string concatenation with multiple statements or
# specific comments might sometimes throw errors, but the vulnerability is in the *construction*
# of the query, allowing an attacker to change its meaning.
# Parameterized queries completely prevent this.