6

“静态”查询是始终保持不变的查询。例如,Stackoverflow 上的“标签”按钮,或 Digg 上的“7 天”按钮。简而言之,它们总是映射到特定的数据库查询,因此您可以在设计时创建它们。

但我试图弄清楚如何在用户基本上决定如何在运行时创建数据库查询的情况下进行“动态”查询。例如,在 Stackoverflow 上,您可以组合标签并以您选择的方式过滤帖子。这是一个动态查询,尽管它非常简单,因为您可以组合在标签的世界中。一个更复杂的例子是如果你可以结合标签和用户。

首先,当您有一个动态查询时,听起来您不能再使用替换 api 来避免 sql 注入,因为查询元素将取决于用户决定在查询中包含的内容。除了使用字符串追加之外,我看不到如何构建此查询。

其次,查询可能跨越多个表。例如,如果 SO 允许用户根据用户和标签进行过滤,并且这些可能存在于两个不同的表中,则构建查询比仅附加列和 WHERE 子句要复杂一些。

我该如何实施这样的事情?

4

4 回答 4

2

第一条规则是允许用户在 SQL 表达式中指定,但不能在 SQL语法中指定值。所有查询语法都应该由您的代码指定,而不是用户输入。用户指定的值可以作为查询参数提供给 SQL。这是限制 SQL 注入风险的最有效方法。

许多应用程序需要通过代码“构建” SQL 查询,因为正如您所指出的,某些表达式、表连接、按条件排序等取决于用户的选择。当您逐段构建 SQL 查询时,有时很难确保结果是有效的 SQL 语法。

我研究了一个名为的 PHP 类Zend_Db_Select,它提供了一个 API 来帮助解决这个问题。如果您喜欢 PHP,您可以查看该代码以获取想法。它不处理任何可以想象的查询,但它做了很多。

其他一些 PHP 数据库框架也有类似的解决方案。

于 2008-11-10T18:07:26.673 回答
1

虽然不是通用解决方案,但您可以采取一些步骤来缓解动态但安全的查询问题。

列值属于基数是任意值的一组值的条件不需要是动态的。考虑使用 instr 函数或使用您加入的特殊过滤表。只要知道列数,这种方法就可以很容易地扩展到多列。使用这种方法可以轻松处理对用户和标签的过滤。

当过滤条件中的列数是任意的但又很小时,请考虑对每种可能性使用不同的静态查询。

只有当过滤条件中的列数是任意的并且可能很大时,您才应该考虑使用动态查询。在这种情况下...

为了避免 SQL 注入,请构建或获取一个库来防御该攻击。虽然难度更大,但这并非不可能完成的任务。这主要是关于在要过滤的值中转义 SQL 字符串分隔符。

为了避免昂贵的查询,请考虑使用专门为此目的设计的视图和一些预先逻辑来限制这些视图将如何被调用。就开发人员的时间和精力而言,这是最具挑战性的。

于 2008-11-10T18:27:16.010 回答
0

那么选项必须映射到某些东西。

如果您仍然为选项使用参数,则SQL 查询字符串CONCAT不是问题。

于 2008-11-10T18:01:17.420 回答
0

如果您使用 python 访问您的数据库,我建议您使用Django 模型系统。对于 python 和其他语言(尤其是在 ruby​​ on rails 中),有许多类似的 api。通过避免使用 SQL 直接与数据库对话,我节省了很多时间。

示例链接

#Model definition
class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name

模型使用(这实际上是一个插入语句)

from mysite.blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()

查询变得更加复杂 - 你传递一个查询对象,你可以向它添加过滤器/排序元素。当您最终准备好使用查询时,Django 会创建一个 SQL 语句来反映您调整查询对象的所有方式。我认为它很可爱。

这种抽象的其他优点

  • 您的模型可以通过 Django 创建为具有外键和约束的数据库表
  • 支持许多数据库(Postgresql、Mysql、sql lite 等)
  • DJango 分析您的模板并从中创建一个自动管理站点
于 2008-11-10T20:11:03.007 回答