【问题标题】:How to create dynamic and safe queries如何创建动态和安全的查询
【发布时间】:2010-09-21 16:11:32
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 为了提出抽象建议:您使用什么语言与您的数据库对话?您使用的是哪个数据库?
  • 您的数据库非常重要。哪个关系型数据库?其次,你是否愿意限制。您是否愿意说您只能搜索 10 个标签... 11 是禁止的?

标签: sql database dynamic


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

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

    【讨论】:

      【解决方案3】:

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

      来自the example link

      #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 分析您的模板并从中创建一个automatic admin site

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2015-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-09
          • 2018-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多