PDO 参数根本不起作用

发布于 2024-11-02 14:25:50 字数 594 浏览 1 评论 0原文

我正在查看一些代码并将其数据库部分更改为使用 PDO。到目前为止,除了我准备好的声明中的参数之外,一切都工作正常。由于某种原因,下面的代码根本不起作用。这两个 $_GET 变量基本上用于特定页面上的排序目的。查询本身无需使用参数即可正常工作,如果我手动将“ORDER BY id DESC”放在末尾,也可以正常工作。我似乎无法让它使用可变参数。这是代码:

$sort = $_GET['sort'];
$order = $_GET['order'];
$statement = $db->prepare('SELECT uid, id, fname, lname, ext, uname
  , email, access, created, modified, last_login, enabled 
  FROM users 
  ORDER BY :col :or');
$statement->bindParam(':col', $sort);
$statement->bindParam(':or', $order);
$statement->execute();
$num = $statement->rowCount();

有什么建议吗?

谢谢

I am going through some code and changing the database part of it to use PDO. Everything is working fine so far except for parameters in my prepared statement. For some reason, the below code isn't working at all. The two $_GET variables are basically used for sorting purposes on a specific page. The query itself works fine without using the parameters, and if I manually put "ORDER BY id DESC" at the end, that works fine too. I just can't seem to get it working with variable parameters. Here's the code:

$sort = $_GET['sort'];
$order = $_GET['order'];
$statement = $db->prepare('SELECT uid, id, fname, lname, ext, uname
  , email, access, created, modified, last_login, enabled 
  FROM users 
  ORDER BY :col :or');
$statement->bindParam(':col', $sort);
$statement->bindParam(':or', $order);
$statement->execute();
$num = $statement->rowCount();

Any suggestions?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧故 2024-11-09 14:25:50

当将参数作为参数传递给 ORDER BY 子句时,它们将被视为文字表达式。如果要按列或别名排序,则需要传递标识符。在 MySQL 中,它们由不带引号的字符串表示,或者最好由反引号引起来的字符串表示,例如

ORDER BY `fname`

类似地,方向常量,当存在时必须使用两个关键字 ASCDESC< /代码>。我不确定如果您尝试使用参数(它将被评估为表达式)会发生什么。


这是我过去使用允许的可排序列的映射来完成此操作的方法......

$orderCols = array(
    'firstName' => 'fname',
    'lastName'  => 'lname'
);
$sort = isset($_GET['sort'], $orderCols[$_GET['sort']])
    ? $orderCols[$_GET['sort']
    : 'uid'; // some sane default

$order = isset($_GET['order']) && $_GET['order'] == 'DESC'
    ? 'DESC' : 'ASC';

$query = sprintf('SELECT uid, id, fname, lname, ext, uname, email, access, created, modified, last_login, enabled FROM users ORDER BY `%s` %s',
    $sort, $order);
$statement = $db->prepare($query);

When passing parameters as the arguments to an ORDER BY clause, they are treated as literal expressions. If you want to order by a column or alias, you need to pass an identifier. In MySQL, these are represented by either an unquoted string, or preferably, a backtick quoted string, eg

ORDER BY `fname`

Similarly, the direction constant, when present must use either of the two keywords ASC or DESC. I'm not sure what happens if you attempt to use a parameter (which will be evaluated as an expression).


Here's how I've done it in the past using a map of allowed orderable columns...

$orderCols = array(
    'firstName' => 'fname',
    'lastName'  => 'lname'
);
$sort = isset($_GET['sort'], $orderCols[$_GET['sort']])
    ? $orderCols[$_GET['sort']
    : 'uid'; // some sane default

$order = isset($_GET['order']) && $_GET['order'] == 'DESC'
    ? 'DESC' : 'ASC';

$query = sprintf('SELECT uid, id, fname, lname, ext, uname, email, access, created, modified, last_login, enabled FROM users ORDER BY `%s` %s',
    $sort, $order);
$statement = $db->prepare($query);
坏尐絯℡ 2024-11-09 14:25:50

使用参数作为伪关键字显然是行不通的!
这就是使用参数可以防止 SQL 注入攻击的(部分)原因。

当然,由于您可以操纵字符串,因此您可以在其中插入“DESC”/“ASC”,从而重新打开整个 SQL 注入漏洞。

因此 :col 将不会被接受为字段。至于 $order 我会推荐像

伪代码(不是真正的 php)这样

if uppercase($order) <> 'DESC' then $order = 'ASC';
$query = 'select ... '+ $order;

的代码显式测试将任何注入代码转换回“ASC”,从而可以安全地像这样破解它。

当然,对于字段,您也可以对所有可能的字段名称进行显式测试。只要您确保可能的结果只能是有效字段名称,您就可以了,但这是如履薄冰。

警告
既然您(可能)又回到了操作查询字符串的状态,那么您也回到了 SQL 注入的领域,所以要非常小心您所做的事情。

Using parameters as pseudo-keywords will just plain not work!
This is (part of) the reason why using parameters protects against SQL-injection attacks.

Of course since you can manipulate the string you can just insert 'DESC'/'ASC' in there, reopening the whole SQL-injection hole.

So the :col will not be accepted as a field. And as regards the $order I would recommend code like

pseudo code (not real php)

if uppercase($order) <> 'DESC' then $order = 'ASC';
$query = 'select ... '+ $order;

The explicit test transforms any injection code back into 'ASC' making it safe to hack it like this.

Of course for the field you can also do an explicit test for all the possible field names. As long as you make sure the possible outcomes can only be valid field names you are good, but it's treading on thin ice.

Warning
Now that you are (potentially) back into manipulating query-strings you are also back into SQL-injection land, so be super careful with what you do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文