【发布时间】:2013-08-04 06:24:17
【问题描述】:
我开始了解使用 MySQLi 和 PDO 时准备好的语句是如何工作的,第一步,我启用了 MySQL 查询监控,如下所述:How can I view live MySQL queries?。然后我创建了以下测试:
使用mysqli:
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) {
$stmt->bind_param("i", $user);
$user = "''1''";
服务器日志:
130802 23:39:39 175 Connect ****@localhost on testdb 175 Prepare SELECT * FROM users WHERE username =? 175 Execute SELECT * FROM users WHERE username =0 175 Quit
使用 PDO:
$user = "''1''";
$sql = 'SELECT * FROM user WHERE uid =?';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->bindParam(1, $user, PDO::PARAM_INT);
服务器日志:
130802 23:41:42 176 Connect ****@localhost on testdb 176 Query SELECT * FROM user WHERE uid ='\'\'1\'\'' 176 Quit
但是,两者都提供相同的结果:
uid: 0
username: admin
role: admin
注意:uid = 0 是正确的,因为intval("''1''") = 0
这里有什么重要的:
PDO 查询如何在向 MySQL 发送不同的查询时得到相同的结果?
SELECT * FROM user WHERE uid ='\'\'1\'\''
我从 PHP 手册中只找到一个指示:http://www.php.net/manual/en/pdo.prepare.php
注意:
模拟的预处理语句不与数据库通信 服务器所以 PDO::prepare() 不会检查语句。
但我不确定 MySQL 如何处理此查询并将'\'\'1\'\'' 替换为0。在这种情况下,如果使用 PDO 监控查询将不准确,同时,使用 PDO 更好地了解发送到 MySQL 而不是 MySQLi 的确切查询。
更新: 将参数类型frm整数更改为字符串后:
MySQLi 日志:
188 Prepare SELECT * FROM awa_user WHERE username =? 188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\'' 188 Quit
PDO 日志:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\'' 189 Quit
这意味着 MySQLi 和 PDO 在使用字符串时会在发送到 MySQL 之前转义数据,而对于整数,mysqli 在发送查询之前应用 intval() 或类似的东西,Bill 也回答这是正确的。
【问题讨论】:
-
这与准备好的语句有什么关系?
-
Ì第一个代码sn-p,为什么将
$user设置为''1''?当你绑定它时,你使用i(整数)。然后,当您将$user设置为''1''时,MySQL 可能不会将其识别为数字,而只是将其设置为 0(零)。 -
@SverriM.Olsen:我假设攻击者输入了这个值,我想查看查询日志是如何发送到 MySQL 的,考虑
$user将是的任何数据...... -
@YourCommonSense:这个对prepared statement的理解的核心,这个是如何深入工作的,有什么不清楚的,我可以解释一下。此外,如果仍然使用错误的关键字进行搜索,请查看返回的错误结果,这表明在执行任何查询之前验证用户输入很重要。
-
你的问题是mysql如何在原始查询中评估
''1''字符串。关于松散类型转换的很常见的问题。