Skip to main content

SQL Injection - Headers

Need

Prevention of SQL injection in headers and application fields

Context

  • Usage of Java 8 for developing applications with enhanced features and performance improvements.
  • Usage of javax.servlet-api for developing Java web applications with Servlets
  • Usage of mysql-connector-java for connecting to MySQL database in Java applications

Description

Non compliant code

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class VulnerableServlet extends HttpServlet {

private static final String DB_URL = "jdbc:myDriver:myDatabase";
private static final String USER = "username";
private static final String PASS = "password";

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String idClient = request.getHeader("idClient");
try {
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM Clients WHERE id = " + idClient;
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
// Process the result set
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

In the above code, the idClient value is directly taken from the HTTP header and appended to the SQL query without any sanitization or parameterization. This is a classic case of SQL Injection vulnerability.

When the doGet method is called, it retrieves the idClient value from the HTTP header. This value is then directly used to construct a SQL query, which is then executed.

The vulnerability lies in the fact that an attacker could modify the idClient header to include additional SQL commands. For example, an attacker could set the idClient header to 1; DROP TABLE Clients;--. This would result in the following SQL command being executed: SELECT * FROM Clients WHERE id = 1; DROP TABLE Clients;--. This would delete the entire Clients table from the database.

This vulnerability could be exploited to perform any number of malicious actions, including data theft, data modification, and denial of service.

Steps

  • Use parameterized queries or prepared statements to handle user input in SQL statements.
  • Validate and sanitize user input before using it in SQL statements.
  • Implement proper input validation to ensure that only valid data is accepted.
  • Use a whitelist approach to validate and sanitize user input, allowing only specific characters or patterns.
  • Implement proper error handling to prevent detailed error messages from being displayed to users.
  • Regularly update and patch the application and its dependencies to fix any known vulnerabilities.
  • Implement access controls and authentication mechanisms to restrict unauthorized access to sensitive data.
  • Educate developers about secure coding practices and the risks associated with SQL injection vulnerabilities.

Compliant code

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class SecureServlet extends HttpServlet {

private static final String DB_URL = "jdbc:myDriver:myDatabase";
private static final String USER = "username";
private static final String PASS = "password";

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String idClient = request.getHeader("idClient");
if (idClient != null && idClient.matches("[0-9]+")) {
try {
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
String sql = "SELECT * FROM Clients WHERE id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, Integer.parseInt(idClient));
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// Process the result set
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

The above code fixes the SQL Injection vulnerability in the original code by implementing the following changes:

  1. Parameterized Queries: The SQL query is now parameterized using a PreparedStatement. This means that the idClient value is not directly concatenated into the SQL query string, which prevents SQL Injection attacks.

  2. Input Validation: The idClient value is validated using a regular expression to ensure that it only contains numeric characters. This is a whitelist approach to input validation, which is more secure than a blacklist approach. If the idClient value does not match the regular expression, the SQL query is not executed.

  3. Error Handling: The code includes a try-catch block to handle any exceptions that occur when executing the SQL query. This prevents detailed error messages from being displayed to users, which could provide information useful to an attacker.

  4. Access Controls and Authentication: Although not shown in this code snippet, it is recommended to implement access controls and authentication mechanisms to restrict unauthorized access to sensitive data.

  5. Secure Coding Practices: This code demonstrates secure coding practices, such as using parameterized queries and validating user input, which can help prevent SQL Injection vulnerabilities.

References