SQL Injection: Exploitation, Detection and Prevention

Kapeed
13 min readJan 2, 2023

--

SQL Injection Attack and Its Prevention

SQL injection is a type of cyber attack in which an attacker injects malicious code into a website’s Structured Query Language (SQL) database. The goal of the attack is to gain unauthorized access to or manipulate the data stored in the database.

Here’s how an SQL injection attack typically works:

  1. The attacker identifies a vulnerable website or web application that uses SQL to interact with a database.
  2. The attacker crafts a malicious SQL statement and injects it into a form field, URL parameter, or other input fields on the website.
  3. The website’s application code executes the injected SQL statement, which can cause the database to perform unintended actions or reveal sensitive information.

For example, consider a website that has a login form where users can enter their username and password. The website’s application code might use an SQL statement like this to check the user’s credentials:

SELECT * FROM users WHERE username='$username' AND password='$password';

If an attacker entered the following values for the username and password fields:

username: ' OR '1'='1
password: anything

The resulting SQL statement would be:

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

This statement would always evaluate as true because the OR operator will return true if either of the conditions on either side of it is true. As a result, the attacker would be able to log in to the website as any user without knowing their correct username or password.

SQL injection attacks can also be used to modify or delete data in the database, or to execute arbitrary code on the server. They can have serious consequences for both the security and integrity of a website or web application. To prevent SQL injection attacks, it’s important to properly validate and sanitize user input and use prepared statements with placeholders for any dynamic SQL queries.

Impact

  1. Loss of sensitive data: An attacker may be able to access or manipulate sensitive data, such as financial records, customer information, or trade secrets.
  2. Unauthorized actions: An attacker may be able to execute unauthorized actions, such as deleting or modifying data.
  3. Financial losses: An SQL injection attack can result in financial losses for the affected organization, either through direct financial damage or through the costs of responding to and recovering from the attack.
  4. Damage to reputation: An SQL injection attack can damage an organization’s reputation and lead to a loss of trust from customers and other stakeholders.
  5. Legal liabilities: An SQL injection attack may also result in legal liabilities for the affected organization, depending on the nature and extent of the attack and any relevant laws or regulations.

Exploitation

SQL injection vulnerabilities occur when a web application or website includes user input in an SQL statement without properly validating or sanitizing it. This allows an attacker to inject malicious code into the statement, which can be used to gain unauthorized access to or manipulate the data in the database.

To exploit an SQL injection vulnerability, an attacker needs to:

1. Identify a potential SQL injection vulnerability

The attacker will first need to identify a potential SQL injection vulnerability in the target application or website. This may involve analyzing the application’s code and looking for user input that is directly included in an SQL query without proper validation or sanitization.

Example of how an attacker might identify a potential SQL injection vulnerability in an application’s code:

$username = $_POST['username']; 
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result) > 0) {
// login successful
} else {
// login fail
}

In this example, the attacker might notice that the $username and $password variables are directly included in the SQL query without any validation or sanitization. This could potentially allow an attacker to inject malicious code into the query through the $username or $password variables. To exploit this vulnerability, the attacker would need to craft a malicious payload and inject it into the query through the $username or $password variables. For example, the attacker might try injecting a payload that allows them to bypass the password check or gain unauthorized access to the database.

2. Craft a malicious payload

The attacker will then craft a malicious payload that exploits the identified vulnerability. This may involve injecting malicious code into an SQL statement through user input, such as adding additional commands or altering the intended logic of the query.

Example of a potentially malicious payload that an attacker might use to exploit an SQL injection vulnerability:

$product_id = "';DROP TABLE orders; SELECT * FROM products WHERE id = 1 OR id = '";

In this example, the attacker has injected a payload into the $product_id variable that causes the orders table to be deleted when the query is executed, and then selects all rows from the products table where the id is either 1 or the original value of $product_id. This could allow the attacker to delete important data and potentially manipulate the results of the query.

3. Execute the payload

The attacker will then execute the payload, either by directly interacting with the application or website or by using automation tools. One example of an automation tool that an attacker might use to execute a payload is SQLMap. SQLMap is an open-source tool that automates the process of detecting and exploiting SQL injection vulnerabilities. It can be used to perform various types of attacks, such as retrieving data from a database, modifying data, and even taking control of the underlying operating system.

4. Analyze the results

The attacker will then analyze the results of the payload to determine the impact and whether it was successful in exploiting the vulnerability.

Simple example of how an attacker might exploit an SQL injection vulnerability:

// assume that the following user input is not properly validated or sanitized

$product_id = $_GET['product_id'];

// the following query is vulnerable to SQL injection

$query = "SELECT * FROM products WHERE id = $product_id";

// the attacker could exploit the vulnerability by injecting a malicious payload
// such as adding an additional command to the query

$product_id = "'; DROP TABLE orders; --";

// the resulting query would look like this:
// SELECT * FROM products WHERE id = ''; DROP TABLE orders; --'
// this query would delete the "orders" table, potentially causing significant damage

In this example, the attacker has injected a malicious payload into the $product_id variable that causes the orders table to be deleted when the query is executed. This could cause significant damage and disruption to the application or database.

Exploiting SQL injection vulnerability requires some knowledge of SQL and web application development.

Detection

There are several ways to detect SQL injection attacks:

  1. Regularly monitoring web server logs and application logs for suspicious activity, such as unusual database queries or error messages.
  2. Using a web application firewall (WAF) to detect and block malicious traffic. A WAF can analyze incoming HTTP requests and block those that contain potentially harmful SQL statements.
  3. Performing regular security testing, including penetration testing and vulnerability scanning, to identify and fix SQL injection vulnerabilities in your web applications.
  4. Educating users and developers about the risks of SQL injection attacks and the importance of input validation and sanitization.

It’s important to note that no single method is foolproof, and a combination of different approaches is usually the most effective way to detect and prevent SQL injection attacks. It’s also important to regularly review and update your security measures to keep up with new threats and vulnerabilities.

Detection Example

Imagine a website that has a search form that allows users to search for products in a database by entering a keyword. The website’s application code uses the following SQL statement to search the database:

SELECT * FROM products WHERE name LIKE '%$keyword%';

Here’s how an attacker might attempt to exploit this website using an SQL injection attack:

The attacker identifies the vulnerable search form on the website and crafts a malicious SQL statement, such as:

'; DELETE FROM products WHERE 1=1; --

The attacker injects the malicious SQL statement into the search form by entering it into the keyword field.

The website’s application code executes the following SQL statement:

SELECT * FROM products WHERE name LIKE '%; DELETE FROM products WHERE 1=1; --%';

This SQL statement would delete all rows from the products table, causing serious damage to the website’s database.

To detect this attack, the website’s server logs or application logs might show an unusually large number of DELETE statements being executed, indicating that an SQL injection attack is in progress. Alternatively, a WAF set up to monitor HTTP requests could detect the malicious SQL statement and block it before it reaches the application code. Regular security testing and user education could also help prevent the attack from occurring in the first place.

Prevention

There are several ways to prevent SQL injection attacks:

1. Validate and sanitize user input

It’s important to ensure that all user input is properly validated and sanitized before being used in an SQL statement. This can help prevent attackers from injecting malicious code into your application.

For example, you can use input validation techniques like filtering, pattern matching, and type checking to ensure that user input meets certain criteria.

a. Input filtering

It involves checking user input for certain criteria before using it in a SQL query. For example, you might check that a user-provided number is actually a number before using it in a numerical comparison in your query. This can help prevent attackers from injecting malicious input that doesn’t match the expected data type. Here is an example of input filtering in PHP:

$user_id = $_POST['user_id']; 
if (!is_numeric($user_id)) {
// If the user_id is not numeric, exit or show an error message exit("Invalid user ID");
}
// Now we can safely use the $user_id in our SQL query, knowing that it is a number
$query = "SELECT * FROM users WHERE user_id = $user_id";

b. Parameterized queries

With parameterized queries, you can specify placeholders for user input in your SQL statement, and then provide the actual input as separate parameters. The database library you are using will then automatically escape and quote the input, making it safe to use in the query. Here is an example of using a parameterized query in PHP with the PDO library:

$user_id = $_POST['user_id'];
$query = "SELECT * FROM users WHERE user_id = :user_id";
$stmt = $pdo->prepare($query);
$stmt->bindParam(':user_id', $user_id); $stmt->execute();

c. Pattern matching

It involves using regular expressions to check that user input matches a certain pattern or format. For example, you might use pattern matching to ensure that a user-provided email address or phone number is in the correct format. Here is an example of using pattern matching in PHP to validate a user-provided email address:

$email = $_POST['email']; 
if (!preg_match("/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$/", $email)) { // If the email does not match the pattern, exit or show an error message exit("Invalid email address");
}
// Now we can safely use the $email in our SQL query, knowing that it is a valid email address
$query = "SELECT * FROM users WHERE email = '$email'";

d. Type matching

It is a technique that can be used to prevent SQL injection attacks by ensuring that user input matches the expected data type. For example, suppose you have a form on your website that allows users to enter their ages. You might use type matching to check that the user input is actually a number before using it in an SQL query.

$age = $_POST['age'];

if (is_numeric($age)) {
// age is a number, so it's safe to use in an SQL query
$query = "SELECT * FROM users WHERE age = $age";
// execute the query
} else {
// age is not a number, so it could be malicious input
// do not execute the query and show an error message
echo "Please enter a valid age.";
}

By using type matching, you can ensure that the user input is a number before using it in the SQL query. This can help prevent attackers from injecting malicious input that doesn’t match the expected data type.

Useful Functions

Functions like mysql_real_escape_string() in PHP or addslashes() in JavaScript to escape special characters that might be used in an injection attack. One way to prevent SQL injection attacks is to use functions that escape special characters in user input. These functions can help ensure that user input is properly quoted and escaped, making it difficult for attackers to inject malicious code into your SQL statements.

In PHP, the mysql_real_escape_string() function can be used to escape special characters in a string that is to be used in a MySQL database. The function takes a string as an argument and returns the escaped string.

Here is an example of using mysql_real_escape_string() in PHP:

$username = $_POST['username'];
// Escape special characters in the username
$username = mysql_real_escape_string($username);
$query = "SELECT * FROM users WHERE username = '$username'";

In JavaScript, the addslashes() function can be used to escape special characters in a string. The function takes a string as an argument and returns the escaped string.

Here is an example of using addslashes() in JavaScript:

var username = document.getElementById('username').value; 
// Escape special characters in the username
username = addslashes(username);
var query = "SELECT * FROM users WHERE username = '" + username + "'";

Using functions like mysql_real_escape_string() in PHP or addslashes() in JavaScript can help protect against SQL injection attacks by properly quoting and escaping user input. It's important to note, however, that these functions should not be relied upon as the sole means of protection against SQL injection, as they can be bypassed by more advanced attacks. It is recommended to use a combination of input validation, sanitization, and prepared statements to help prevent SQL injection.

2. Use prepared statements with placeholders

Prepared statements allow you to separate the structure of an SQL statement from the data that is inserted into it. This can help prevent SQL injection attacks by allowing you to safely insert dynamic data into an SQL statement without having to worry about sanitizing it. For example, consider the following PHP code:

$stmt = $db->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();

In this example, the ? characters act as placeholders for the dynamic data ($username and $password). The data is then bound to the placeholders using the bind_param() function, which ensures that it is properly escaped and inserted into the SQL statement.

3. Use stored procedures

Stored procedures are pre-defined SQL statements that are stored in the database and can be called by the application as needed. Using stored procedures can help prevent SQL injection attacks because they allow you to separate the logic of your application from the data it manipulates. This makes it more difficult for attackers to inject malicious code into your application.

Stored procedures can be an effective way to prevent SQL injection attacks because they allow you to separate the definition of the SQL statements from the input parameters that are passed to the procedure. This can help ensure that user input is properly sanitized and quoted, making it difficult for attackers to inject malicious code into your SQL statements.

Here is an example of creating and calling a stored procedure in MySQL:

-- Create the stored procedure 
CREATE PROCEDURE add_user (IN username VARCHAR(255), IN email VARCHAR(255))
BEGIN
INSERT INTO users (username, email) VALUES (username, email); END;

-- Call the stored procedure
CALL add_user('john', 'john@example.com');

Here is an example of calling a stored procedure in PHP using the PDO library:

$username = $_POST['username']; 
$email = $_POST['email'];
$query = "CALL add_user(:username, :email)";
$stmt = $pdo->prepare($query);
$stmt->bindParam(':username', $username);
$stmt->bindParam(':email', $email);
$stmt->execute();

Using stored procedures can help prevent SQL injection attacks by separating the definition of the SQL statements from the input parameters, ensuring that user input is properly sanitized and quoted. It’s important to note, however, that stored procedures should be carefully designed and reviewed to ensure that they are secure and do not introduce vulnerabilities

4. Use parameterized queries

Parameterized queries are similar to prepared statements in that they allow you to insert dynamic data into an SQL statement in a safe and secure way. However, unlike prepared statements, which are compiled and stored on the server, parameterized queries are sent to the database as plain text and are compiled by the database server when they are executed. This can make them slightly less efficient than prepared statements, but they can still be an effective way to prevent SQL injection attacks.

Parameterized queries are a technique that can be used to prevent SQL injection attacks by separating the definition of the SQL statement from the input parameters that are passed to the query. With parameterized queries, you can specify placeholders for user input in your SQL statement, and then provide the actual input as separate parameters. The database library you are using will then automatically escape and quote the input, making it safe to use in the query.

Here is an example of using a parameterized query in MySQL:

SET @username = 'john'; 
SET @email = 'john@example.com';

PREPARE stmt FROM "INSERT INTO users (username, email) VALUES (?, ?)";
EXECUTE stmt USING @username, @email;

Here is an example of using a parameterized query in PHP with the PDO library:

$username = $_POST['username']; 
$email = $_POST['email'];
$query = "INSERT INTO users (username, email) VALUES (:username, :email)";
$stmt = $pdo->prepare($query);
$stmt->bindParam(':username', $username);
$stmt->bindParam(':email', $email);
$stmt->execute();

Using parameterized queries can help prevent SQL injection attacks by separating the definition of the SQL statement from the input parameters, and automatically escaping and quoting the input. It’s important to note, however, that parameterized queries should be used correctly and in combination with other security measures, such as input validation and sanitization, to provide the most effective protection against SQL injection.

5. Use an object-relational mapping (ORM) framework

ORM frameworks provide a layer of abstraction between your application and the database, allowing you to write database queries using object-oriented code rather than raw SQL. This can make it easier to prevent SQL injection attacks because the ORM framework handles the task of sanitizing user input and generating safe SQL statements for you.

An object-relational mapping (ORM) framework is a tool that maps objects in a program to the rows in a database table. ORM frameworks can make it easier to work with databases in a program by providing a high-level, object-oriented interface for interacting with the data.

One of the benefits of using an ORM framework is that it can help prevent SQL injection attacks by automatically handling the quoting and escaping of user input. This can make it more difficult for attackers to inject malicious code into your SQL statements.

Here is an example of using an ORM framework, in this case, Doctrine, to insert a new user into a database in PHP:

$user = new User(); 
$user->setUsername('john');
$user->setEmail('john@example.com');
$entityManager->persist($user);
$entityManager->flush();

In this example, the User object is created and its properties are set using setter methods. The persist() method is then called to add the object to the database, and the flush() method is called to save the changes to the database. The ORM framework will handle the translation of the object properties to the appropriate columns in the database table and will automatically quote and escape the user input to prevent SQL injection attacks.

Using an ORM framework can be a helpful way to prevent SQL injection attacks by automatically handling the quoting and escaping of user input. It’s important to note, however, that ORM frameworks should be used correctly and in combination with other security measures, such as input validation and sanitization, to provide the most effective protection against SQL injection.

In Conclusion

It’s important to note that no single method is foolproof, and a combination of different approaches is usually the most effective way to prevent SQL injection attacks. It’s also important to regularly review and update your security measures to keep up with new threats and vulnerabilities.

--

--

Kapeed
Kapeed

Written by Kapeed

Cybersecurity Researcher | Digital Content Creator

No responses yet