CC: | marco [...] nethype.de |
Subject: | security issue: placeholders will string-interpolate without quoting, executing parameters as sql |
Hi!
We currently run into a DBD::mysql where placeholders (?) in prepared statements get replaced with the string value of the parameter without any quoting, leading to parameter values being executed as sql.
I don't have a testcase, but looking at the code in dbdimp.C parse_params, it's quite obvious that this is the case under certain conditions.
If you follow the logic for case '?', then the parameter value will be interpolated without any quoting when bind_type_guessing is false and the column is numeric - SQL_NUMERIC will cause is_num to be set, nothing will re-set it, and the code will then take the string(!) value of the parameter value and interpolate it as sql commands instead of quoting it.
For example, the following code will probably trigger this issue:
$st = $dbh->prepare ("delete from users where uid = ?");
$st->bind_param (1, undef, { TYPE => DBI::SQL_NUMERIC });
$st->execute ("uid");
Which would result in:
delete from users where uid = uid
I haven't tested the code above, but following the logic for case '?' is quite easy and somehow it must be possible to have bind_type_guessing off, while having a numeric type for a parameter.
The code is overall quite weirdly inefficient (why does it call parse_number when is_num is false for example), so this is probably the result of some refactoring, having been undetected because bind_param is rarely used.
I think this is a security bug because ? placeholders should NEVER EVER treat the bound value as sql code and execute it.