是否有更动态的方法来清理ORDER BY

时间:2013-10-22 05:18:49

标签: php mysql request sql-injection

我有一个来自,其中两个字段是以下

<select name="sortfield">
    <option value="name" selected="selected">Name</option>
    <option value="price">Price</option>
    <option value="id">ID Code</option>
</select>
<select name="sortdir">
    <option value="asc" selected="selected">Ascending</option>
    <option value="desc">Descending</option>
</select>

这是通过下一页的$_REQUEST[]获得的,然后将其添加到查询中以确定查询结果的排序方式,快速,脏,未经过消毒的方式是

$query .= "ORDER BY ".$_REQUEST['sortfield']." ".$_REQUEST['sortdir'];

显然这可能是sql注入的问题,我可以解决的一种方法是更改​​值并在进行查询交换值时有一个切换案例,类似这样

switch($_REQUEST['sortfield'])
{
    case '5524879':
        $query .= "ORDER BY name";
        break;
    case '4587532':
        $query .= "ORDER BY price";
        break;
    default:
        $query .= "ORDER BY id";
}

虽然这可以帮助防止sql注入它不是非常动态,因为如果查询/表结构发生变化,每次都必须更改页面,我想知道是否有更动态的方法来清理字符串而不是必须使用一个switch ... case

2 个答案:

答案 0 :(得分:1)

更动态的方法是使用show fields创建一个表字段数组,并在检查sortfield

的值时将其用作白名单
if ( !in_array( $_REQUEST['sortfield'], $table_fields ) ) {
    // error
}

我还建议不要使用$ _REQUEST。你应该知道变量的来源。

  

$ _REQUEST中的变量通过GET提供给脚本,   POST和COOKIE输入机制因此可以修改   远程用户,不可信任。的存在和秩序   此数组中列出的变量是根据PHP定义的   variables_order配置指令。

答案 1 :(得分:1)

是的,对于order by子句,您只能格式化动态标识符,而不是针对白名单进行检查。

if (!empty($_GET['sortfield']))
{
    $query .= "ORDER BY `".str_replace("`","``",$_GET['sortfield'])."`";
} else {
    $query .= "ORDER BY id";
}

请注意,它会保护您免受注入,但不会从SQL语法错误中保存 - 因此,最好还是验证字段名称。

此外,表中可能没有id字段,因此此代码也不是非常动态。所以,最好还是坚持白名单。毕竟, 不是很难。有时手动修改比自动修改更好。