参数化的 SQL 列?
Posted
技术标签:
【中文标题】参数化的 SQL 列?【英文标题】:Parameterized SQL Columns? 【发布时间】:2010-09-11 11:36:53 【问题描述】:我有一些代码利用参数化查询来防止注入,但我还需要能够动态构造查询,而不管表的结构如何。这样做的正确方法是什么?
这是一个示例,假设我有一个包含名称、地址、电话列的表格。我有一个网页,我在其中运行 Show Columns 并使用它们作为选项填充选择下拉列表。
接下来,我有一个名为 Search 的文本框。此文本框用作参数。
目前我的代码如下所示:
result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);不过,我从中得到了一种恶心的感觉。我使用参数化查询的原因是为了避免使用 escape。此外,escape 可能不是为转义列名而设计的。
我怎样才能确保这按我的预期工作?
编辑: 我需要动态查询的原因是架构是用户可配置的,我不会去修复任何硬编码的东西。
【问题讨论】:
【参考方案1】:某些数据库中的列名可以包含空格,这意味着您必须引用列名,但如果您的数据库不包含此类列,只需在拼接之前通过正则表达式或某种检查运行列名SQL:
if ( $column !~ /^\w+$/ )
die "Bad column name [$column]";
【讨论】:
【参考方案2】:在标准 SQL 中,将分隔标识符括在双引号中。这意味着:
SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?
将从具有所示大小写的名为 SomeTable 的表中进行选择(不是名称的大小写转换版本),并将条件应用于具有所示大小写的名为 SomeColumn 的列。
就其本身而言,这并不是很有帮助,但是...如果您可以将带有双引号的 escape() 技术应用于通过 Web 表单输入的名称,那么您可以相当自信地构建您的查询。
当然,您说您想避免使用转义 - 实际上您不必在提供 ? 的参数上使用它。占位符。但是,如果您将用户提供的数据放入查询中,则需要保护自己免受恶意人员的侵害。
不同的 DBMS 有不同的方式来提供分隔标识符。例如,MS SQL Server 似乎使用方括号 [SomeTable] 而不是双引号。
【讨论】:
【参考方案3】:根据对枚举可能架构值的表的另一个查询的结果创建列。在第二个查询中,您可以将选择硬编码为用于定义架构的列名。如果没有返回行,则输入的列无效。
【讨论】:
【参考方案4】:我使用 ADO.NET 并使用 SQL 命令和 SQLParameters 来处理 Escape 问题的那些命令。因此,如果您也在 Microsoft 工具环境中,我可以说我非常成功地使用它来构建动态 SQL 并保护我的参数
祝你好运
【讨论】:
【参考方案5】:诀窍是对您的转义和验证例程充满信心。我使用自己的 SQL 转义函数,该函数为不同类型的文字重载。我无法直接从用户输入中插入表达式(与引用的文字值相反)。
尽管如此,它还是可以做到的,我推荐一个单独的 - 严格的 - 函数来验证列名。允许它只接受一个标识符,比如
/^\w[\w\d_]*$/您必须依赖可以对自己的列名做出的假设。
【讨论】:
【参考方案6】:无需传递列名,只需传递您编码的标识符,该标识符将使用硬编码表转换为列名。这意味着您无需担心会传递恶意数据,因为所有数据要么是合法翻译的,要么已知是无效的。伪代码:
@columns = qw/Name Address Telephone/;
if ($columns[$param])
$query = "select * from contacts where $columns[$param] = ?";
else
die "Invalid column!";
run_sql($query, $search);
【讨论】:
硬编码不是我的选择,谢谢你的建议! 我的意思不是对列名进行硬编码,而是从界面传递它们。您可以动态获取列列表,并且仍然使用上述相同的解决方案。只是不要将列名作为传递数据的一部分——这将保护您免受任何 SQL 注入。 +1 是的,我想说:让用户输入数据,但不要让用户提供代码。以上是关于参数化的 SQL 列?的主要内容,如果未能解决你的问题,请参考以下文章
使用参数化的 SqlCommand 是不是使我的程序免受 SQL 注入的影响?