Reputation: 1770
I understand that using prepared statement prevents injection as the prepared statement execution consists of two stages: prepare and execute.
OK, but I do not really get what is going on if a bound parameter value is then used as a User-Defined Variables in MySQL.
Is the initially safe bound parameters process can be used for execution (and therefore injection) in STEP 2 ?
// The user input that may be the target for injection
$userInput = "input";
// STEP 1 -------------------
$q = "SET @param1 = :param1;";
// Execute query to set mysql user-defined variables
$param = [
'param1' => $userInput
];
$stmt = $pdo->prepare($q);
$stmt->execute($param);
// STEP 2 -------------------
// Query DB with User-Defined Variables
$q = "
SELECT ...
WHERE
table.field1 = @param1 OR
table.field2 = @param1 OR
table.field3 = @param1
";
// Query
$stmt = $pdo->query($q);
// STEP 3 -------------------
// Fetch Data
$row = $stmt->fetch();
I use this to avoid multiple similar named parameters like in the following example hereafter as
you cannot use a named parameter marker of the same name more than once in a prepared statement, unless emulation mode is on
from manual. It's a mess to maintain for complex queries:
$q = "
SELECT ...
WHERE
table.field1 = :param1_1 OR
table.field2 = :param1_2 OR
table.field3 = :param1_2
";
$param = [
'param1_1' => $userInput
'param1_2' => $userInput
'param1_3' => $userInput
];
$stmt = $pdo->prepare($q);
$stmt->execute($param);
Upvotes: 3
Views: 338
Reputation: 562651
Yes, you can assume that a user variable takes the place of a single scalar value in a query, just like a bound parameter placeholder. It's an effective protection against SQL injection.
Proof: Try to perform an SQL injection using a user variable.
SET @s = 'Robert''; DROP TABLE Students;--';
SELECT * FROM Students WHERE name = @s;
This does NOT drop the table. It probably returns nothing, because there is no student with that strange, long name (unless you go to school with Little Bobby Tables).
However, I wonder if a query like this:
SELECT ...
WHERE
table.field1 = @param1 OR
table.field2 = @param1 OR
table.field3 = @param1
Indicates that field1, field2, and field3 should really be a single field in a child table. If you're searching for the same value in multiple columns, it could be a repeating group. For example, if it's phone1, phone2, phone3, that's a multi-valued attribute that should be stored in one column over multiple rows in a child table. Then you can search with a single parameter.
Upvotes: 5
Reputation: 108460
Q: Is the initially safe bound parameters process can be used for execution (and therefore injection) in STEP 2 ?
A: The pattern shown in the code in the question does not open up a SQL Injection vulnerability.
A user defined-variable used as a value in a SQL statement (as shown in the pattern in the question) is seen by MySQL as a value. That is, MySQL will not interpret the contents of the user-defined variable as part of the SQL text.
To get that to happen, to introduce a SQL Injection vulnerability, we would would need to dynamically construct SQL text and get that prepared/executed with the MySQL PREPARE
/EXECUTE
SQL statements.
https://dev.mysql.com/doc/refman/5.7/en/prepare.html
So, yes. Using a user-defined variable (as shown in the code in the question) does not in itself introduce SQL Injection vulnerability.
(But, just so there is no misunderstanding... it is possible to write vulnerable code, both with and without user-defined variables.)
Upvotes: 2