参数化的SQL列?

时间:2020-03-06 14:28:03  来源:igfitidea点击:

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

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

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

目前,我的代码如下所示:

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

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

我如何确保它能按照我的意图工作?

编辑:
我需要动态查询的原因是该模式是用户可配置的,并且我将不会修复任何硬编码的内容。

解决方案

无需传递列名,只需传递我们编码的标识符即可,该标识符将使用硬编码表转换为列名。这意味着我们不必担心会传递恶意数据,因为所有数据都是合法转换的,或者已知是无效的。伪代码:

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

run_sql($query, $search);

诀窍是要对转义和验证例程充满信心。我使用自己的SQL转义函数,该函数对不同类型的文字进行了重载。我无处可直接从用户输入中插入表达式(与带引号的文字值相反)。

尽管如此,还是可以做到的,我还是建议使用一个单独且严格的函数来验证列名。允许它仅接受一个标识符,例如

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

我们必须依赖可以对自己的列名进行的假设。

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

祝你好运

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

在标准SQL中,将定界标识符括在双引号中。这意味着:

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

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

就其本身而言,这不是很有帮助,但是...如果我们可以对通过Web表单输入的名称应用带双引号的escape()技术,则可以相当放心地建立查询。

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

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

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

if ( $column !~ /^\w+$/ ) {
  die "Bad column name [$column]";
}