Skip to main content
Educational Purpose Only - This documentation is for learning security concepts in a controlled environment. Never attempt SQL injection on systems without explicit authorization.

Overview

SQL Injection (SQLi) is a critical web security vulnerability that allows attackers to interfere with database queries by injecting malicious SQL code through user input fields. In this demo, the vulnerable login form concatenates user input directly into SQL queries, enabling complete authentication bypass.

Severity Rating

Vulnerable Code

The vulnerable implementation in vulnerable/app.py:26 uses string formatting to construct SQL queries:
vulnerable/app.py
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # VULNERABLE: SQL Injection
        query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
        print(f"Query ejecutada: {query}")
        
        cursor.execute(query)
        user = cursor.fetchone()
        
        if user:
            session['user_id'] = user['id']
            session['username'] = user['username']
            return redirect('/dashboard')

Why This Is Dangerous

The vulnerability exists because:
  1. Direct String Concatenation: User input is embedded directly into the SQL query using f-strings
  2. No Input Validation: The application doesn’t sanitize or validate special characters
  3. No Parameterization: The query doesn’t use prepared statements or parameterized queries
  4. Error Exposure: SQL errors are displayed to users (vulnerable/app.py:43), revealing database structure

Exploitation Steps

1

Access the Vulnerable Login

Navigate to the vulnerable application login page:
https://auth-vulnerable.onrender.com/login
2

Inject SQL Payload

Enter the following credentials to bypass authentication:
Username: admin
Password: x' OR '1'='1
This creates the query:
SELECT * FROM users WHERE username = 'admin' AND password = 'x' OR '1'='1'
The OR '1'='1' always evaluates to TRUE, bypassing password verification.
3

Verify Access

Upon successful injection, you’ll be:
  • Logged in as the first user in the database (typically admin)
  • Redirected to /dashboard
  • Granted full session access without knowing the actual password

Impact Analysis

Confirmed in Demo

  • Complete authentication bypass
  • Access to admin accounts
  • Session hijacking
  • Database error information disclosure

Real-World Risks

  • Full database extraction
  • Data modification/deletion
  • Privilege escalation
  • Remote code execution (in extreme cases)
  • Compliance violations (GDPR, PCI-DSS)

Advanced Exploitation

Beyond authentication bypass, SQL injection can be used for:

Data Extraction

' UNION SELECT id, username, password, email, role, created_at FROM users --

Database Enumeration

' AND 1=0 UNION SELECT null, sqlite_version(), null, null, null, null --

Boolean-Based Blind SQLi

' AND (SELECT COUNT(*) FROM users) > 5 --

Secure Implementation

The secure version in secure/app.py:54-63 properly prevents SQL injection:
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username', '').strip()
        password = request.form.get('password', '')
        
        # Input validation
        if not username or not password:
            flash('Usuario y contraseña son requeridos', 'danger')
            return render_template('login.html')
        
        if len(username) > 50:
            flash('Usuario inválido', 'danger')
            return render_template('login.html')
        
        connection = create_connection()
        cursor = connection.cursor()
        
        # SECURE: Parameterized query
        query = "SELECT * FROM users WHERE username = %s"
        cursor.execute(query, (username,))
        user = cursor.fetchone()
        
        # SECURE: Hash verification separate from SQL
        if user and check_password_hash(user['password'], password):
            session['user_id'] = user['id']
            return redirect('/dashboard')
        else:
            flash('Credenciales incorrectas', 'danger')

Mitigation Strategies

Always use parameterized queries or prepared statements:
# Good: Parameterized
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))

# Bad: String formatting
cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")
Prepared statements ensure user input is treated as data, never as SQL code.
Validate all user input:
# Length validation
if len(username) > 50:
    return error

# Character whitelist
import re
if not re.match(r'^[a-zA-Z0-9_]+$', username):
    return error

# Strip whitespace
username = username.strip()
ORMs like SQLAlchemy automatically use parameterized queries:
# SQLAlchemy example
user = User.query.filter_by(username=username).first()
Database users should have minimal necessary permissions:
-- Create limited user
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE ON webapp_db.* TO 'webapp'@'localhost';
-- NO DELETE, DROP, or admin privileges
Never expose SQL errors to users:
try:
    cursor.execute(query, params)
except sqlite3.Error as e:
    # Log error securely
    logger.error(f"Database error: {e}")
    # Show generic message to user
    flash('An error occurred. Please try again.', 'danger')

Detection and Prevention

Code Review Checklist

  • All database queries use prepared statements/parameterized queries
  • No string concatenation or f-strings in SQL queries
  • Input validation on all user-supplied data
  • Generic error messages (no SQL error exposure)
  • Database user has minimal required privileges
  • SQL injection testing in CI/CD pipeline

Testing Tools

SQLMap

Automated SQL injection testing tool
sqlmap -u "http://target.com/login" \
  --data="username=test&password=test" \
  --level=5 --risk=3

Burp Suite

Manual testing and vulnerability scanning
  • Intruder for payload testing
  • Scanner for automated detection

References

Next Steps

Explore related vulnerabilities:

Build docs developers (and LLMs) love