PYTHON

Preventing SQL Injection with Python Parameterized Queries

Secure your Python applications against SQL injection attacks by using parameterized queries with database connectors like `psycopg2` for PostgreSQL.

import psycopg2
from psycopg2 import sql

def get_user_data(user_id):
    conn = None
    try:
        # Replace with your actual database connection details
        conn = psycopg2.connect(
            dbname="mydatabase",
            user="myuser",
            password="mypassword",
            host="localhost"
        )
        cur = conn.cursor()

        # CORRECT: Using a parameterized query
        # The database driver handles escaping the value securely
        query = sql.SQL("SELECT * FROM users WHERE id = %s;")
        cur.execute(query, (user_id,)) # Pass parameters as a tuple

        user_data = cur.fetchone()
        return user_data
    except psycopg2.Error as e:
        print(f"Database error: {e}")
        return None
    finally:
        if conn:
            cur.close()
            conn.close()

def create_user(username, email, password_hash):
    conn = None
    try:
        conn = psycopg2.connect(
            dbname="mydatabase",
            user="myuser",
            password="mypassword",
            host="localhost"
        )
        cur = conn.cursor()

        # CORRECT: Using a parameterized query for INSERT
        insert_query = sql.SQL("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s);")
        cur.execute(insert_query, (username, email, password_hash))
        conn.commit()
        print(f"User {username} created successfully.")
    except psycopg2.Error as e:
        print(f"Database error: {e}")
        conn.rollback() # Rollback in case of error
    finally:
        if conn:
            cur.close()
            conn.close()

# --- NEVER DO THIS (Vulnerable to SQL Injection) ---
def get_user_data_vulnerable(user_id):
    conn = None
    try:
        conn = psycopg2.connect(
            dbname="mydatabase",
            user="myuser",
            password="mypassword",
            host="localhost"
        )
        cur = conn.cursor()
        # FLAWED: Direct string concatenation of user input
        # An attacker could inject malicious SQL here
        query = f"SELECT * FROM users WHERE id = {user_id};"
        cur.execute(query)
        user_data = cur.fetchone()
        return user_data
    except psycopg2.Error as e:
        print(f"Vulnerable query error: {e}")
        return None
    finally:
        if conn:
            cur.close()
            conn.close()

if __name__ == "__main__":
    # Example usage (secure)
    user = get_user_data(1)
    print(f"User data (secure): {user}")

    # Example usage (vulnerable) - DO NOT USE IN PRODUCTION
    # Imagine user_id comes from user input, e.g., request.args.get('id')
    malicious_input = "1 OR 1=1; --" # This could retrieve all users or drop tables
    user_vulnerable = get_user_data_vulnerable(malicious_input)
    print(f"User data (vulnerable): {user_vulnerable}")

    # Example of creating a user securely
    create_user("john_doe", "[email protected]", "hashed_password_abc")
How it works: This Python snippet demonstrates how to prevent SQL injection vulnerabilities using parameterized queries with the `psycopg2` library for PostgreSQL. Instead of directly concatenating user input into SQL strings, parameterized queries pass data values separately to the database driver. The driver then properly escapes and sanitizes these values, ensuring they are treated as data, not executable SQL code, effectively neutralizing injection attempts.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs