我可以使用pdo准备的语句绑定标识符(表或字段名)或语法关键字吗?

jexiocij  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(385)

我正在处理一个动态查询,它使用变量来指定表、字段/列和要搜索的值。我在phpmyadmin(手动键入查询)中以及通过将变量连接到一个完整的查询中,使查询在没有变量的情况下按预期工作。
但是,当我使用 bindParam() 或者 bindValue() 为了绑定变量,它返回一个空数组。
这是我的密码:

function search_db($db, $searchTerm, $searchBy, $searchTable){
    try{
        $stmt = $db->prepare('
            SELECT 
                * 
            FROM 
                ?
            WHERE 
                ? LIKE ?
        ');
        $stmt->bindParam(1, $searchTable);
        $stmt->bindParam(2, $searchBy);
        $stmt->bindValue(3, '%'. $searchTerm.'%');
        $stmt->execute();
    } catch(Exception $e) {
        return array();
    }
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

// database initialization, creates the $db variable
require(ROOT_PATH . "include/database.php");
$matches = search_db($db, 'search term', 'myColumn', 'myTable');

var_dump($matches);

预期结果:数据库中的行数组
实际结果:空数组

pkbketx9

pkbketx91#

我可以使用pdo prepared语句绑定标识符(表或字段名)或语法关键字吗?

不幸的是,prepared语句只能表示数据文本。所以,一个非常常见的陷阱是这样的查询:

$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm  = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();

根据pdo设置,此查询将产生错误(在使用实际准备语句的情况下)或文本字符串 'id' 在字段集中(在模拟的情况下)。
因此,开发人员必须自己处理标识符—pdo对此没有任何帮助。
要使动态标识符安全,必须遵守两条严格规则:
正确格式化标识符
根据硬编码的白名单进行验证。
要格式化标识符,必须应用以下两条规则:
将标识符括起来。
把背虱翻一番,从里面逃走。
格式化之后,可以安全地将$table变量插入到查询中。所以,代码是:

$field = "`".str_replace("`","``",$field)."`";
$sql   = "SELECT * FROM t ORDER BY $field";

然而,尽管这样的格式对于order by这样的情况已经足够了,但是对于大多数其他情况,有一种不同类型的注入的可能性:让用户选择他们可以看到的表或字段,我们可能会泄露一些敏感信息,如密码或其他个人数据。所以,最好是对照允许值列表检查动态标识符。下面是一个简单的例子:

$allowed = array("name","price","qty");
$key     = array_search($_GET['field'], $allowed);
$field   = $allowed[$key];
$query   = "SELECT $field FROM t"; //value is safe

对于关键字,规则是相同的,但当然没有可用的格式-因此,只有白名单是可能的,应该使用:

$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC'; 
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe

另请参见php文档中的用户贡献注解:pdo::quote上的用户注解

相关问题