基本上,我想要做的是:
mysql_query("SELECT ... FROM ... ORDER BY $_GET[order]")
他们显然可以通过在其中添加无意义来轻松地创建SQL错误,但mysql_query
仅允许您执行1个查询,因此他们不能放置1; DROP TABLE ...
之类的内容。
除了创建语法错误外,恶意用户是否可以造成任何损害?
如果是,我该如何清理查询?
$_GET['order']
变量基于类似SQL的语法构建了很多逻辑,所以我真的不想改变格式。
为了澄清,$_GET['order']
不仅仅是一个字段/列。它可能类似于last_name DESC, first_name ASC
。
答案 0 :(得分:30)
是的,SQL注入攻击可以使用未转义的ORDER BY子句作为向量。这里有一个解释如何利用它以及如何避免这个问题:
http://josephkeeler.com/2009/05/php-security-sql-injection-in-order-by/
该博客文章建议使用白名单来验证ORDER BY参数,这几乎肯定是最安全的方法。
要响应更新,即使该子句很复杂,您仍然可以编写一个针对白名单验证它的例程,例如:
function validate_order_by($order_by_parameter) {
$columns = array('first_name', 'last_name', 'zip', 'created_at');
$parts = preg_split("/[\s,]+/", $order_by_parameter);
foreach ($parts as $part) {
$subparts = preg_split("/\s+/", $part);
if (count($subparts) < 0 || count($subparts) > 2) {
// Too many or too few parts.
return false;
}
if (!in_array($subparts[0], $columns)) {
// Column name is invalid.
return false;
}
if (count($subparts) == 2
&& !in_array(strtoupper($subparts[1]), array('ASC', 'DESC')) {
// ASC or DESC is invalid
return false;
}
}
return true;
}
即使ORDER BY子句很复杂,它仍然仅使用您提供的值(假设您不允许用户手动编辑它)。您仍然可以使用白名单进行验证。
我还应该补充一点,我通常不喜欢在URL或UI中的其他位置公开我的数据库结构,并且通常会在URL中的参数中对这些内容进行别名,并使用哈希将其映射到实际值。
答案 1 :(得分:17)
不要指望当时的SQL注入不会导致问题;不允许任何SQL注入。如果不出意外,恶意攻击者可以定义一个非常复杂的订单,这可能会导致数据库严重减速。
答案 2 :(得分:6)
我更喜欢进行白名单,并将http参数字符串视为与插入SQL查询的字符串分开。
在下面的PHP示例中,数组键将是作为http参数传递的值,根据您的Web界面,是不同排序方案的某种符号标签。对于这些相应的排序方案,数组值将是我们想要插入SQL的内容,例如,列名或表达式。
<?php
$orderby_whitelist = array(
"name" => "last_name, first_name",
"date" => "date_created",
"daterev" => "date_created DESC",
"DEFAULT" => "id"
);
$order = isset($_GET["order"])
? $_GET["order"]
: "DEFAULT";
$order_expr = array_key_exists($order, $orderby_whitelist)
? $orderby_whitelist[$order]
: $orderby_whitelist["DEFAULT"];
mysql_query("SELECT ... FROM ... ORDER BY $order_expr")
这有以下优点:
即使您无法使用查询参数,也可以防御SQL注入。如果客户端传递了无法识别的值,则代码会忽略它并使用默认顺序。
您不必清理任何内容,因为数组中的键和值都是由程序员编写的。客户输入只能选择您允许的其中一个选项。
您的网络界面未显示您的数据库结构。
您可以制作与SQL表达式或替代ASC / DESC相对应的自定义订单,如上所示。
您可以在不更改Web界面的情况下更改数据库结构,反之亦然。
我在演示文稿中SQL Injection Myths & Fallacies以及我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming中介绍了此解决方案。
答案 3 :(得分:2)
围绕变量$_GET['order']
构建的逻辑在变量$order_sanitized
上使用时应该同样有效。为什么不首先清理输入,然后执行逻辑以使其适合SELECT
语句?
答案 4 :(得分:-1)
它仍然是潜在的SQL注入点。您取决于mysql_query
的内部实施。如果在更高版本中他们将其更改为使用多个查询,该怎么办?
您可以使用mysql_real_escape_string
。