“静态”查询始终保持不变。例如,Stackoverflow上的“标签”按钮,或Digg上的“7天”按钮。简而言之,它们始终映射到特定的数据库查询,因此您可以在设计时创建它们。
但我试图弄清楚如何进行“动态”查询,其中用户基本上规定了如何在运行时创建数据库查询。例如,在Stackoverflow上,您可以组合标记并以您选择的方式过滤帖子。这是一个动态查询,虽然是一个非常简单的查询,因为你可以组合在一起的标签世界。一个更复杂的例子是你可以组合标签和用户。
首先,当你有一个动态查询时,听起来你不能再使用替换api来避免sql注入,因为查询元素将取决于用户决定包含在查询中的内容。除了使用字符串append之外,我无法看到如何构建此查询。
其次,查询可能跨越多个表。例如,如果SO允许用户基于用户和标签进行过滤,并且这些可能存在于两个不同的表中,那么构建查询比仅添加列和WHERE子句要复杂一些。
我如何实现这样的目标?
答案 0 :(得分:2)
第一条规则是允许用户在SQL表达式中指定值,但不允许SQL 语法。所有查询语法都应该由您的代码按字面指定,而不是用户输入。用户指定的值可以作为查询参数提供给SQL。这是限制SQL注入风险的最有效方法。
许多应用程序需要通过代码“构建”SQL查询,因为正如您所指出的,某些表达式,表连接,按标准排序等取决于用户的选择。当您逐个构建SQL查询时,有时很难确保结果是有效的SQL语法。
我参与了一个名为Zend_Db_Select
的PHP类,它提供了一个API来帮助解决这个问题。如果你喜欢PHP,你可以查看代码以获取想法。它不处理任何可以想象的查询,但它做了很多。
其他一些PHP数据库框架也有类似的解决方案。
答案 1 :(得分:1)
虽然不是一般解决方案,但您可以采取以下步骤来缓解动态且安全的查询问题。
列值属于基数为任意值的一组值的标准不需要是动态的。考虑使用instr函数或使用您加入的特殊过滤表。只要已知列数,此方法就可以轻松扩展到多个列。使用这种方法可以轻松处理对用户和标签的过滤。
如果过滤条件中的列数是任意的但很小,请考虑针对每种可能性使用不同的静态查询。
仅当过滤条件中的列数是任意且可能很大时,您才应考虑使用动态查询。在这种情况下......
为了安全地从SQL注入,要么构建或获得防御该攻击的库。虽然更难,但这不是一项不可能完成的任务。这主要是关于在要过滤的值中转义SQL字符串分隔符。
为了避免昂贵的查询,请考虑使用专门为此目的制作的视图和一些前期逻辑来限制调用这些视图的方式。就开发人员的时间和精力而言,这是最具挑战性的。
答案 2 :(得分:0)
选项必须映射到某些东西。
如果您仍然使用选项的参数,则SQL查询字符串CONCAT
不是问题。
答案 3 :(得分:0)
如果您使用python访问数据库,我建议您使用Django model system。 python和其他语言都有许多类似的api(特别是在rails上的ruby中)。我通过避免使用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语句。我觉得它很可爱。
这种抽象的其他优点