Java

Java

Made by DeepSource

Prepared statements must not be generated from dynamically created strings JAVA-S0083

Security
Critical

The code creates an SQL prepared statement from a String that was formed dynamically. This may be vulnerable to SQL injection attacks.

While prepared statements are generally safer than directly building queries and executing them, their effectiveness is reduced when they are created dynamically, especially when the queries are created from untrusted input. One use case of this is when parameters such as table or column names need to be selected dynamically. Prepared statements do not generally allow such values to be parameterized, so we may end up resorting to string concatenation again:

// ...

String table = request.getParameter("table");
String user = request.getParameter("user");
String pass = request.getParameter("pass");

String query = "SELECT * FROM " + table + " WHERE user = ? AND pass = ?"; // Unsafe...

PreparedStatement pStmt = connection.prepareStatement(query);

pStmt.setString(1, user);
pStmt.setString(2, pass);

ResultSet res = pStmt.execute();

// ...

A savvy attacker would be free to pass an input such as "users WHERE (user = ? AND pass = ?) OR 1=1 --" in the table parameter which would allow them to trick the backend into fetching all rows of the users table. The resultant query can be interpreted as shown below:

SELECT * FROM users WHERE (user = ? AND pass = ?) OR 1=1 -- WHERE user = ? AND pass = ?
|   /* Commented part is ignored; (a AND b) OR true always evaluates to true. */
V
SELECT * FROM users WHERE 1=1
|   /* We don't need the where clause either. */
V
SELECT * FROM users

There are a number of strategies that could prevent this:

  • The table parameter could be checked against a whitelist to ensure only valid table names are accepted
  • Escape any special characters in user input. Note that if this is not done properly, you may end up with a situation such as this...
  • Predefine allowed values as constants, and make the client send an identifier (an integer for example) that is mapped to one of the allowed values.

Exceptions

If there is a solid guarantee that such an attack cannot occur, this issue can be safely ignored.

References