I have a simple stored procedure:
DELIMITER $$
CREATE PROCEDURE `findUserByName`(IN `name` VARCHAR(36))
BEGIN
set @name = name;
PREPARE findStmt FROM 'SELECT * FROM user WHERE name=?';
EXECUTE findStmt USING @name;
END$$
I call it in PHP with the prepare method:
$stmt = $mysqli->prepare('CALL findUserByName(?)');
$stmt->execute([$inputName]);
I have 2 questions about the above code:
-
This assignment statement
set @name = name;
appears somewhat redundant, can I directly use the parametername
? MySQL doesn’t allow me to useUSING name
, I have also tried changing the parameter name to@name
, but it will not be recognized. -
Since I have used the prepare method in PHP, is it safe to concatenate the parameter with SQL?
set @sql = CONCAT('SELECT * FROM user WHERE name=''', name, ''''); PREPARE findStmt FROM @sql; EXECUTE findStmt;
2
Answers
EXECUTE
. I agree this is weird and unsatisfying, because you must set a user-defined variable (the type with the@
sigil) that seems redundant.https://dev.mysql.com/doc/refman/8.0/en/execute.html says:
No, it’s not safe to concatenate strings into your dynamic SQL, if the string may contain untrusted content. This is called SQL injection, and it’s a common source of errors or data breaches.
What happens in your example above, if someone enters their name as "O’Reilly"?
You may see advice to "use prepared statements" to protect your code from SQL injection, but merely using
PREPARE
is not magic. It does not bless unsafe SQL to make it safe. The advice should be "use parameters." It is necessary to usePREPARE
to use parameters, but it’s the parameters, not thePREPARE
, that is the important part to make it safe.Select a distinct name for the procedure parameter, avoiding duplication with the column name. You can then use the parameter directly in the query: