如果我尝试运行以下PHP代码,我会得到一个
你知道为什么吗?我在另一个网站上使用相同的代码,它可以正常工作。在非对象上调用成员函数fetch()。
<?php
$username = ($_GET ['user']);
try {
$dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');
} catch (PDOException $e) {
echo $e->getMessage();
}
$sth = $dbh->query( "SELECT user, captcha
FROM xf_captcha WHERE user='$username'" );
print_r($sth->fetch());
?>
编辑:
$sth = $dbh->query( "SELECT username, user_state, last_activity, alerts_unread, conversations_unread, message_count
FROM xf_user WHERE username='$user'" );
$row = $sth->fetch();
EDIT2:
如果我做得更多,这看起来是否安全?
<?php
$username = ($_GET ['user']);
try {
$dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');
} catch (PDOException $e) {
echo $e->getMessage();
}
$sth = $dbh->prepare("SELECT username, captcha, timestamp
FROM xf_captcha
WHERE username = :username", array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $username));
print_r($sth->fetch());
?>
答案 0 :(得分:2)
您的代码在问题的顶部有变量$username
,但您在底部有$user
。
您是否也意味着使用相同的变量?
$username = ($_GET ['user']);
$sth = $dbh->query( "SELECT username, user_state, last_activity, alerts_unread, conversations_unread, message_count
FROM xf_user WHERE username='$user'" );
// ^^ Should this ALSO be $username ?
$row = $sth->fetch();
编辑:好的,现在你对PDO::ATTR_EMULATE_PREPARES
感到很可爱。观察这一点:
数据库和表结构:
Database changed
mysql> show tables
-> ;
+----------------+
| Tables_in_prep |
+----------------+
| users |
+----------------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+---------+--------+
| id | userid | pass |
+----+---------+--------+
| 1 | Fluffeh | mypass |
+----+---------+--------+
1 row in set (0.00 sec)
从您的复制的一些PHP代码,添加了PDO属性:
<?php
//$username = ($_GET ['user']);
$username="Fluffeh";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="user2693017";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="Oh my' or 1=1 or 'm=m";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="(select id from users limit 1)";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
// Changed this one to be a non-string, you might be checking an ID instead.
$username="(select id from users limit 1)";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id=$username" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="bob'; drop table users; \
";
// This one is tricker to do in PHP code. I could easily enter this into a text field however.
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
//$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
输出:
Trying to use Fluffeh.
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use user2693017.
----------------------------------------
Trying to use Oh my' or 1=1 or 'm=m.
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use (select id from users limit 1).
----------------------------------------
Trying to use (select id from users limit 1).
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use bob'; drop table users; \
.
----------------------------------------
哦,我离开最后一个直到最后的原因是这个输出现在在我的数据库中:
mysql> show tables;
Empty set (0.00 sec)
是的,没错,我只是放了一张桌子。让我再说一遍,我有一个选择语句,并且带着一点点诡计我输入了一个值,任何半脑和一些恶意意图的人都可以进入文本字段,并删除你的表。
现在,如果你正确设置,你可能会为select语句设置一个不同的用户,并且只从你的数据库授予他们select
权限,以阻止这种事情的发生 - 但老实说......你不是吗?
显然设置仿真是不够的。说真的,现在请转到read that answer,如果你想在代码中保持安全,请使用准备好的语句并使用params。
答案 1 :(得分:0)
您的Execute语句在哪里被调用?这也在你的->query
内吗?如果不考虑使用以下内容也可以建立更好的查询。:
<?php
$username = ($_GET['user']);
try {
$dbh = new PDO("mysql:host=localhost;dbname=***", '***', '***');
} catch (PDOException $e) {
echo $e->getMessage();
}
$statement = "SELECT user, captcha FROM xf_captcha WHERE user=:username";
//If you have query as a method(Which I don't think so but if you can change "prepare" to your "query"
$sth = $dbh->prepare($statement);
$sth->execute(array(":username" => $username));
$row = $sth->fetch(PDO::FETCH_ASSOC);
?>
在执行括号中,您可以使用数组填充参数:username
以获取变量$username
我认为研究PDO类示例也可能有助于更好地理解PDO和方法(您也可以参考PHP PDO手册)
答案 2 :(得分:-1)
当桌子也不存在时,就会发生这种情况。确保它确实存在,并且由于硬盘驱动器错误而不仅仅是数据库中的持有者。
如果发生这种情况,我建议你重新创建数据库/表,如果phpMyAdmin在尝试阅读时会出现错误&#34;手动&#34;。