Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SQL Injection Demo — Insecure vs. Secure Login (Flask + SQLite)

A small Flask/SQLite login system that demonstrates a classic SQL injection vulnerability side by side with the parameterized-query fix, so you can see exactly why one fails and the other doesn't — using the same payload against both.

image

The vulnerability

The insecure implementation builds its SQL query by directly interpolating user input into the query string:

query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"

Because the input becomes part of the SQL statement itself, an attacker can inject SQL syntax instead of a normal value. Submitting:

Username:  ' OR '1'='1' --
Password:  (anything)

produces the query:

SELECT * FROM users WHERE username = '' OR '1'='1' -- ' AND password = 'anything'
image

'1'='1' is always true, and -- comments out the rest of the query (including the password check), so the query returns the first user in the table — logging the attacker in without valid credentials.

image

The fix

The secure implementation uses a parameterized (prepared) query:

query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
image

The ? placeholders keep the SQL structure fixed. The database compiles the query first, then binds the input as literal data — never as part of the SQL syntax. The exact same injection payload is treated as a plain string to match against username, so the login simply fails.

Project structure

sql-injection-demo/
├── main.py            # Flask app with a mode toggle (Insecure / Secure)
├── insecure.py         # Vulnerable login function
├── secure.py            # Fixed login function using parameterized queries
├── userdatabase.py       # Creates users.db with a seeded test account
├── templates/
│   ├── login.html
│   └── home.html

Running it

pip install -r requirements.txt
python userdatabase.py    # one-time setup, creates users.db
python main.py

Open http://127.0.0.1:5000, seeded test account is admin / SuperSecret123.

Try logging in with the payload above in each mode:

  • Insecure Mode → logs you in without the correct password
  • Secure Mode → correctly rejects it

Why this matters

SQL injection has been on the OWASP Top 10 for over a decade and remains one of the most common ways web applications get compromised. The underlying lesson generalizes beyond SQL: never build a command by concatenating untrusted input into it. Parameterized queries, prepared statements, and proper input handling exist in essentially every language/database combination for exactly this reason.

References

About

A vulnerable Flask login app compared against a secure version using parameterized queries demonstrating how SQL injection works and how to prevent it.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages