LAB_01 / DATABASE Beginner

Queries under your control. Explore the boundary between data and code.

Experiment hint

First, try ordinary input. Then use an example from the lesson and compare the result in the vulnerable and protected variants. The code panels highlight the boundaries relevant to the attack or defense.

SQL Injection

01 / THEORY · ⚠ VULNERABLE CODE

Vulnerable variant

SQL Injection lets an attacker change SQL queries executed by an application. It can be used to bypass authentication or read, modify and delete database records.

In the vulnerable variant, user input is inserted directly into a SQL query. For example, this method checks the submitted credentials:


public function getUnsafe($username, $password) {
    $stmt = $this->pdo->query("SELECT * FROM users WHERE username = '$username' AND password = '$password'");
    return $stmt->fetch(); 
}
                    
The query is built by concatenating SQL with user input. Input that changes the SQL structure can alter the query’s behavior.
The getUnsafe method returns the result as an associative array whose keys are column names. The SQL query is:
SELECT * FROM users WHERE username = '$username' AND password = '$password'     
The result contains every column from the users table for the matching username and password. Because getUnsafe is vulnerable, carefully crafted input can change the query’s logic. For example, enter the following payload (input designed to demonstrate the vulnerability):
 ' or ''='  
as both the username and password. The modified condition can return the first user record even though the supplied values are not valid credentials.

02 / EXPLOIT · TEST THE INPUT

03 / DEFENSE · ✓ PROTECTED CODE

Protected variant

In the protected variant, input is passed as query parameters. It is treated as data rather than as part of the SQL structure. This method checks the credentials using a prepared statement:


public function getSafe($username, $password) { 
    $stmt = $this->pdo->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); 
    $stmt->execute([$username, $password]); 
    return $stmt->fetch();
 } 
                    
The query is prepared with placeholders and executed with separate parameter values. The input cannot change the SQL structure.


Parameter binding separates SQL structure from data. Input containing SQL syntax remains a parameter value and cannot change the intended query conditions.

Add a user