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

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

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

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

result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);
但是我从中得到了一种icky的感觉。我使用参数化查询的原因是为了避免使用转义。此外,转义可能不是为转义列名而设计的。

我怎样才能确保这个按照我的意图运作?

修改: 我需要动态查询的原因是架构是用户可配置的,我不会修复硬编码的任何内容。

有帮助吗?

解决方案

不要传递列名,只需使用硬编码表传递代码将转换为列名的标识符。这意味着您无需担心传递恶意数据,因为所有数据都是合法翻译的,或者已知无效。 Psudoish代码:

@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来处理那些处理Escape问题的命令。因此,如果您也在Microsoft工具环境中,我可以说我非常有用地构建动态SQL并保护我的参数

祝你好运

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

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

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

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

本身,这不是很有帮助,但是......如果你可以使用双引号将escape()技术应用于通过网络表单输入的名称,那么你可以合理地自信地建立你的查询。

当然,你说你想避免使用转义 - 事实上你不必在你提供的参数上使用它吗?占位。但是,如果要将用户提供的数据放入查询中,则需要保护自己免受恶意攻击者的侵害。

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

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

if ( $column !~ /^\w+$/ ) {
  die "Bad column name [$column]";
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top