Formatted SQL queries can be difficult to maintain, debug and can increase the risk of SQL injection when concatenating untrusted values into the
query. However, this rule doesn’t detect SQL injections (unlike rule S3649), the goal is only to highlight complex/formatted queries.
Ask Yourself Whether
- Some parts of the query come from untrusted values (like user inputs).
- The query is repeated/duplicated in other parts of the code.
- The application must support different types of relational databases.
There is a risk if you answered yes to any of those questions.
Recommended Secure Coding Practices
Sensitive Code Example
$id = $_GET['id'];
mysql_connect('localhost', $username, $password) or die('Could not connect: ' . mysql_error());
mysql_select_db('myDatabase') or die('Could not select database');
$result = mysql_query("SELECT * FROM myTable WHERE id = " . $id); // Sensitive, could be susceptible to SQL injection
while ($row = mysql_fetch_object($result)) {
echo $row->name;
}
Compliant Solution
$id = $_GET['id'];
try {
$conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch(PDO::FETCH_OBJ)) {
echo $row->name;
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
Exceptions
No issue will be raised if one of the functions is called with hard-coded string (no concatenation) and this string does not contain a "$"
sign.
$result = mysql_query("SELECT * FROM myTable WHERE id = 42") or die('Query failed: ' . mysql_error()); // Compliant
The current implementation does not follow variables. It will only detect SQL queries which are concatenated or contain a $
sign
directly in the function call.
$query = "SELECT * FROM myTable WHERE id = " . $id;
$result = mysql_query($query); // No issue will be raised even if it is Sensitive
See