8

我有一些代码利用参数化查询来防止注入,但我还需要能够动态构造查询,而不管表的结构如何。这样做的正确方法是什么?

这是一个示例,假设我有一个包含名称、地址、电话列的表。我有一个网页,我在其中运行Show Columns并使用它们作为选项填充选择下拉列表。

接下来,我有一个名为Search的文本框。此文本框用作参数。

目前我的代码看起来像这样:

result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);

不过,我从中得到一种恶心的感觉。我使用参数化查询的原因是避免使用escape。此外,转义可能不是为转义列名而设计的。

我怎样才能确保这按我的意图工作?

编辑: 我需要动态查询的原因是模式是用户可配置的,我不会去修复任何硬编码的东西。

4

6 回答 6

6

无需传递列名,只需传递您编码的标识符,该标识符将使用硬编码表转换为列名。这意味着您无需担心会传递恶意数据,因为所有数据要么经过合法翻译,要么已知无效。伪代码:

@columns = qw/Name Address Telephone/;
if ($columns[$param]) {
  $query = "select * from contacts where $columns[$param] = ?";
} else {
  die "Invalid column!";
}

run_sql($query, $search);
于 2008-09-19T22:03:17.480 回答
0

诀窍是对您的转义和验证程序充满信心。我使用自己的 SQL 转义函数,该函数为不同类型的文字重载。我无法直接从用户输入插入表达式(与引用的文字值相反)。

尽管如此,它还是可以做到的,我推荐一个单独的 - 并且严格的 - 函数来验证列名。允许它只接受一个标识符,比如

/^\w[\w\d_]*$/

您将不得不依赖您可以对自己的列名做出的假设。

于 2008-09-19T22:10:51.097 回答
0

我使用 ADO.NET 并使用 SQL 命令和 SQLParameters 来处理那些处理 Escape 问题的命令。因此,如果您也在 Microsoft 工具环境中,我可以说我非常成功地使用它来构建动态 SQL 并保护我的参数

祝你好运

于 2008-09-19T22:12:46.337 回答
0

根据对枚举可能架构值的表的另一个查询的结果创建列。在第二个查询中,您可以将选择硬编码为用于定义架构的列名。如果没有返回行,则输入的列无效。

于 2008-09-19T22:15:49.900 回答
0

在标准 SQL 中,您将分隔标识符括在双引号中。这意味着:

SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?

将从具有所示大写字母的名为 SomeTable 的表中进行选择(不是名称的大小写转换版本),并将条件应用于具有所示大写字母的名为 SomeColumn 的列。

就其本身而言,这并不是很有帮助,但是...如果您可以将带有双引号的 escape() 技术应用于通过 Web 表单输入的名称,那么您可以合理自信地构建您的查询。

当然,您说您想避免使用转义 - 实际上您不必在提供 ? 的参数上使用它。占位符。但是,当您将用户提供的数据放入查询中时,您需要保护自己免受恶意人员的侵害。

不同的 DBMS 有不同的方式来提供分隔标识符。例如,MS SQL Server 似乎使用方括号 [SomeTable] 而不是双引号。

于 2008-09-19T22:16:13.380 回答
0

某些数据库中的列名可以包含空格,这意味着您必须引用列名,但如果您的数据库不包含此类列,只需在拼接到 SQL 之前通过正则表达式或某种检查运行列名:

if ( $column !~ /^\w+$/ ) {
  die "Bad column name [$column]";
}
于 2008-09-19T22:16:26.140 回答