Skip to main content

SQL injection

Need

Implementation of proper input validation and the use of parameterized statements or stored procedures to prevent SQL injection attacks.

Context

  • Usage of C# for developing robust and efficient software applications
  • Usage of System.Data.SqlClient for connecting to and interacting with Microsoft SQL Server databases

Description

Non compliant code

using (var connection = new SqlConnection("ConnectionString"))
{
connection.Open();

var query = $"SELECT * FROM Users WHERE Username = '{username}' AND Password = '{password}'";

using (var command = new SqlCommand(query, connection))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Process the data
}
}
}
}

The code above represents a typical SQL Injection vulnerability. The issue lies within the creation of the SQL query. The username and password variables are directly inserted into the query string without any form of validation or sanitization, which opens up the possibility for SQL Injection.

A SQL Injection attack can occur when an attacker modifies the username or password inputs to alter the SQL query, potentially allowing them to view, modify, or delete data from the database.

For example, an attacker could provide the following input for username: admin';--. The resulting SQL query would be SELECT * FROM Users WHERE Username = 'admin';--' AND Password = '{password}'. The -- is a SQL comment, so everything after it would be ignored, effectively bypassing the password check.

This vulnerability can have severe implications, including data breaches and unauthorized access to sensitive data. Therefore, it is crucial to prevent SQL Injection attacks by properly validating and sanitizing user input and using parameterized queries or stored procedures.

Steps

  • Use parameterized queries or prepared statements to ensure that user input is properly sanitized and treated as data rather than executable code.
  • Avoid concatenating user input directly into SQL statements.
  • Validate and sanitize user input before using it in SQL queries.
  • Implement input validation and enforce strong password policies to prevent SQL injection attacks.
  • Consider using an ORM (Object-Relational Mapping) framework that handles SQL queries and parameterization automatically.
  • Regularly update and patch your database management system to protect against known vulnerabilities.

Compliant code

using (var connection = new SqlConnection("ConnectionString"))
{
connection.Open();

var query = "SELECT * FROM Users WHERE Username = @username AND Password = @password";

using (var command = new SqlCommand(query, connection))
{
command.Parameters.Add(new SqlParameter("@username", SqlDbType.VarChar) { Value = username });
command.Parameters.Add(new SqlParameter("@password", SqlDbType.VarChar) { Value = password });

using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Process the data
}
}
}
}

The original code was vulnerable to SQL Injection attacks because it was concatenating user input directly into a SQL statement. This is a dangerous practice as it allows an attacker to manipulate the SQL query by injecting malicious SQL code through the user input fields.

The fixed code now uses parameterized queries to prevent SQL Injection attacks. Instead of directly concatenating the user input into the SQL statement, it uses parameters (@username and @password) that are then filled with the user input values using the Parameters.Add method of the SqlCommand object. This ensures that the user input is properly sanitized and treated as data rather than executable code.

The SqlParameter objects are created with the appropriate SqlDbType (in this case, VarChar) and the user input value. This further ensures that the user input is treated as the correct type of data.

This approach effectively prevents an attacker from injecting malicious SQL code through the user input fields, thus fixing the SQL Injection vulnerability.

References