SQL Injection: A Python Demonstration

Posted on June 26, 2025 by Kasim in Security

Introduction

SQL injection is one of the oldest—and still most dangerous—web-app attacks. It happens when an attacker feeds specially crafted input into your SQL queries, tricking the database into revealing or altering data it shouldn’t. In this post, we’ll:
    1.    See a vulnerable Python example
    2.    Explore several malicious payloads
    3.    Show how parameterized queries neutralize them
    4.    Wrap up with a relaxed, practical note on staying safe

 

When It Matters

Any time you build SQL by inserting or interpolating user input, you open the door to SQLi. Common spots include:
    •    Login forms (WHERE username = … AND password = …)
    •    Search or filter fields
    •    Data-modification operations (INSERT, UPDATE, DELETE)

Whenever you spot code like this, pause and ask: Could this string be used to smuggle SQL?

 

1) Vulnerable Example

import sqlite3
def fetch_user_vulnerable(username):
   conn   = sqlite3.connect('app.db')                        # OPEN DATABASE  
   cursor = conn.cursor()                                    # CREATE CURSOR  
   # ❌ DANGEROUS: unsanitized user input in SQL string  
   query  = f"SELECT * FROM users WHERE username = '{username}';"
   cursor.execute(query)                                     # EXECUTE untrusted SQL  
   results = cursor.fetchall()                               # RETURN ALL ROWS  
   conn.close()                                              # CLOSE CONNECTION  
   return results

If someone passes username = "'; DROP TABLE users; --", the query becomes:

SELECT * FROM users WHERE username = ''; DROP TABLE users; --';

That second statement wipes out your users table!

 

2) Common Malicious Payloads


    1.    Tautology attack

' OR '1'='1

– Turns WHERE into always-true, leaking all rows.

    2.    Union-select data dump

' UNION SELECT credit_card, cvv FROM payments; --

– Appends another SELECT to steal sensitive columns.

    3.    Stacked queries

'; DROP TABLE orders; --

– Executes multiple statements in one go (if supported).

    4.    Time-based blind SQLi

' OR IF(substr(password,1,1)='a',sleep(5),0); --

– Forces the DB to pause, letting attackers infer data one bit at a time.

    5.    Comment injection

admin' --

– Cuts off the rest of your SQL, bypassing checks.

 

3) Neutralizing SQLi with Parameterized Queries

import sqlite3
def fetch_user_safe(username):
   conn   = sqlite3.connect('app.db')                        # OPEN DATABASE  
   cursor = conn.cursor()                                    # CREATE CURSOR  
   # ✅ PLACEHOLDER ensures input is treated strictly as data  
   cursor.execute(
       "SELECT * FROM users WHERE username = ?",             # SQL with placeholder  
       (username,)                                           # PARAMETER TUPLE
   )
   results = cursor.fetchall()                               # RETURN ALL ROWS  
   conn.close()                                              # CLOSE CONNECTION  
   return results

No matter what an attacker feeds in—even "' OR '1'='1" or "; DROP TABLE users; --"—the database engine never mixes it with SQL logic.

 

4) Final Touches: Staying 100% Safe


    •    Always use parameterized APIs (e.g. ?, %s, :name)—never string concatenation.
    •    Validate critical inputs (e.g. enforce username formats).
    •    Limit database privileges so even a successful injection can’t destroy everything.
    •    Keep dependencies up to date (some drivers fix subtle injection holes).

Comments (0)

No comments yet. Be the first to comment!
Leave a Comment

Please make sure you provide a valid e-mail address. A verification email will be sent to confirm your identity before processing your comment.

Your email is only used to send reply notifications if you subscribe and will not be shared with third parties.

Categories