使用动态加载的表和数据库名称在查询中避免 SQL 注入

Posted

技术标签:

【中文标题】使用动态加载的表和数据库名称在查询中避免 SQL 注入【英文标题】:Avoid SQL Injection in query using dynamically loaded tables and database names 【发布时间】:2013-05-02 23:39:02 【问题描述】:

我正在开发一个系统来以一种非常简单的方式管理数据库中的一些表。

系统首先使用 Ajax 加载用户可以查看和管理的数据库。然后加载该数据库中的表,然后加载该表的数据。

我有这样的事情:

$.ajax(
    url : "myUrl.php",
    data : 
        db : $dbSelector.val(),
        table : tableToLoad
    ,
    success : function (json)  /* Some cool stuff here */ 
);

我发现当参数是数据库名称、表或列时,你不能使用参数化查询,所以我不能这样做:

<?php
$query = "SELECT * FROM :db.:table";
$st = $pdo->prepare($query);
$st->execute(
    array(
        "db"=>$db, 
        "table" => $table
    )
);
$rows = $st->fetchAll(PDO::FETCH_OBJ);

我不能使用 mysql_ 或 mysqli_ 过滤,因为我们没有安装它。

【问题讨论】:

是否可以将数据库和表名限制为\w 字符范围?不幸的是,PDO 没有quoteIdentifier 方法。 @Barmar nope... 它将返回:'db'.'table' 并在 mysql 中创建一个错误:“您的 SQL 语法有错误...”错误 42000.raina77ow ,什么意思? 正如PDO::quote 文档中的一个 cmets 中所提到的,解决方法是在调用它之后删除第一个和最后一个字符:substr($dbh-&gt;quote($value), 1, -1) @Barmar。这真的是完成我请求的唯一方法吗?我的意思是......我可以在 PHP 中编写一个函数来完成它(删除我所知道的可以在注入中使用的所有内容)但这不是最佳实践。删除第一个和最后一个字符似乎也不是最好的做法......(不要误解我,我非常感谢你的帮助:]) 恭喜。您刚刚接受了一个答案,使您的问题像太平洋一样容易被注入。 【参考方案1】:

你可以使用:

$db = substr($dbh->quote($db), 1, -1);

或者只是删除所有非字母数字字符:

$db = preg_replace('/\W/', '', $db);

【讨论】:

你对这个 substr 是认真的吗?【参考方案2】:

接受的答案以及它所指的手动注释是一个致命的错误。

PDO::quote 与标识符无关,根本不应该与它们一起使用。 从其输出中删除引号使其实际上对 SQL 注入开放。

巧妙的PDO::quote() 函数的关键在于生成正确的字符串文字。这意味着引用一个字符串并转义里面的引号(如果有的话)。与只进行部分格式化的 mysql_real_escape_string 不同,这是处理字符串的唯一正确方法。 剥夺此功能的一项职责实际上会导致简单的注入。

PDO::quote() 不应该用于格式化标识符。他们需要totally different formatting.

【讨论】:

我知道这不是最好的解决方案(从我的 cmets 你可以看到),但这是我找到工作的唯一想法。我明白你的意思,但我不明白如何使用它......你能再解释一下吗? ***.com/questions/15990857/… 真的吗?也许您误解了我的问题:我有一个动态站点来管理数据库。我将如何获得一组可能的值?这对系统来说意味着很多工作:获取 MySQL 中的数据库/表/字段,然后检查用户发送的内容...

以上是关于使用动态加载的表和数据库名称在查询中避免 SQL 注入的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询加入不同的表和计数

如何MyBatis中使用动态SQL查询与注释

Linqpad - Linq to Sql Ambiguous表和链接服务器名称

如何将ACCESS的表和查询创建成动态的WEB?

如何动态准备 SQL 查询(也包括列名)避免 SQL 注入

sql 数据库中只靠一个数据,查询到所在表和列名