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

21 浏览
0 Comments

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

我正在处理一个动态查询,使用变量来指定表格、字段/列以及要搜索的值。在没有使用变量的情况下,我已经成功地使查询按预期工作,无论是在phpMyAdmin(手动键入查询)还是在代码中通过将变量连接成一个完整的查询来执行。\n然而,当我使用bindParam()bindValue()来绑定变量时,它返回一个空数组。\n以下是我的代码:\n

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);
}
// 数据库初始化,创建$db变量
require(ROOT_PATH . "include/database.php");
$matches = search_db($db, 'search term', 'myColumn', 'myTable');
var_dump($matches);

\n期望的结果:从数据库返回一组行数据\n实际的结果:一个空数组

0
0 Comments

问题的原因是PDO的预处理语句只能绑定数据字面量,无法绑定标识符(例如表名或字段名)或语法关键字。这导致了一个常见的问题,即在查询中无法获取绑定的标识符的值,而只能得到字面字符串。

解决方法是开发者自己来处理标识符的安全性,因为PDO在这方面提供的帮助非常有限。为了使动态标识符安全,必须遵循以下两个严格的规则:

1. 正确格式化标识符:

- 用反引号将标识符括起来。

- 在反引号内部使用两个连续的反引号来转义。

例如,对于表名或字段名的变量$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

通过遵循这些规则,开发者可以安全地处理动态标识符和语法关键字,从而避免注入攻击的风险。

0