SQL WHERE 子句的正则表达式

Posted

技术标签:

【中文标题】SQL WHERE 子句的正则表达式【英文标题】:Regex for SQL WHERE clause 【发布时间】:2008-10-15 13:43:09 【问题描述】:

对于 Web 应用程序,我想构建一个 WHERE 子句并将其提交给服务器。在那里,我会将其附加到查询中。该子句将类似于

LASTNAME LIKE 'Pep%' AND (DOB BETWEEN '19600101' AND '19601231 OR SALARY<35000)

您能否提出一个正则表达式来在将子句提交到 SQL Server 之前对其进行验证?

(是的,当然,我想要 ORDER 子句的正则表达式)

【问题讨论】:

【参考方案1】:

这是一个非常糟糕的主意。我建议您构建一个过滤系统,而不是用户可以在表单中选择各种选项,然后构建正确的 sql 服务器端,而不是让自己面临各种注入攻击。

作为可能出错的示例,请考虑以下内容:

LASTNAME LIKE 'Pep%'--
DROP TABLE People
--

这会将 DROP TABLE 命令注入到您的 SQL 中,这将很难检测到。您当然可以删除 -- 和 /* 之类的内容,但我保证如果您这样做,有人可以找到方法。

【讨论】:

这正是我所做的,通常在 SQL Server 上使用基于表的函数来提高效率。 好答案——我们必须不断劝阻程序员不要制造更多的 SQL 注入漏洞!【参考方案2】:

你不建造

LASTNAME LIKE 'Pep%' AND (DOB BETWEEN '19600101' AND '19601231 OR SALARY<35000)

你构建

LASTNAME LIKE @LastName AND (DOB BETWEEN @dobStart AND @dobEnd OR SALARY<@MaxSalary)

并将这些人作为参数传入。没有正则表达式,不用大惊小怪。

【讨论】:

【参考方案3】:

其他几位评论者指出,允许用户输入来确定 SQL 语法是一个坏主意,并造成了 SQL 注入漏洞。

请注意,评论者对此意见一致,并且 *** 的总“声誉”超过 14,000!

但撇开这一点不谈,您问的是如何编写正则表达式来匹配任意 SQL 语法。答案是你不能用正则表达式来做到这一点

在这种情况下,“常规”表示表达式可以匹配某一类输入语言,也可以用deterministic finite state-machine 表示(有点像流程图)。

例如,匹配 SQL 表达式需要做的一件简单事情是能够匹配嵌套括号。你不能设计一个有限的状态机来匹配嵌套括号,因为它需要能够计算你在任何给定点嵌套括号的深度。为此,您需要解析器来实现堆栈,但这是正则表达式无法做到的。

【讨论】:

有了您的回复,我们现在已经接近 18,000(并且还在上升)。 在他的辩护中,他只希望表达式匹配查询的一部分。但是,它是最有可能需要嵌套括号示例的部分。【参考方案4】:

我想稍微扩展一下 Jimmy 的回答。

LASTNAME LIKE 'Pep%' 

那只是邪恶。永远不要这样做。 SQL 字符串应如下所示:

LASTNAME LIKE @LastName + '%'

现在的问题是,在您的情况下,您根本不知道是否需要进行姓氏检查。您所拥有的只是 SELECT 和 FROM 子句以及 lastname 列的文本框,其中可能有也可能没有值。美好的。这仍然不是像第一个例子那样做的借口。您需要做的是像这样构建您的查询(现在使用 C#,因为您没有提供客户端语言):

//create a place to keep parameters until we can construct the SqlCommand object
List<SqlParameter> params = new List<SqlParameter>();
SqlParameter p;

// the StringBuilder is MUCH more efficient the concatenating strings
// the 1=1 is a placeholder so you can always just append " AND whatever"
StringBuilder sql = new StringBuilder("SELECT ... \nFROM .... \nWHERE 1=1\n");

// Check and add a parameter for the LastName column if needed
if (!String.IsNullOrEmpty(txtLastName.Text))

   sql.AppendLine("AND LASTNAME LIKE @LastName + '%'");
   p = new SqlParameter("@LastName", SqlDbType.VarChar, 50);  // use the actual datatype here
   p.Value = txtLastName.Text;
   params.Add(p);      


// Check and add a parameter for another field if needed
if (!String.IsNullOrEmpty(txtSomeOtherField.Text))

   sql.AppendLine("AND OtherField LIKE @OtherParam + '%'");
   p = new SqlParameter("@OtherParam", SqlDbType.VarChar, 255);
   p.Value = txtSomeOtherField.Text;
   params.Add(p);


// ...  You could also write a method to abstract the code in the if blocks ...

// you haven't told us _how_ the user will specify the order, so I'm leaving that implementation detail out for now
sql.Append(" ORDER BY LastName, OtherField");  

// now we can finally get our SQL String and build the (SAFE!) SqlCommand object:
SqlCommand cmd = new SqlCommand(sql.ToString(), YourSqlConnectionObjectHere);
cmd.Parameters.AddRange(params.ToArray());

现在您有了一个动态生成的 where 子句,没有注入的可能性。它之所以有效,是因为发送到数据库的字符串的 每个 部分都是代码中的精确文字,即使这些文字是通过多个步骤组装而成的。参数中使用的值永远不会替换到字符串中,而是作为数据单独发送到服务器。

当然这是 C# (.Net),但几乎每个现代平台都有某种形式的参数化查询/准备语句功能,您应该使用它。

【讨论】:

【参考方案5】:

where 子句中元素的可能性是巨大的。显然,您有 AND 和 OR 以及 BETWEEN 和 IN 列表以及其他运算符,加上括号,但您也可以调用系统过程、用户定义的函数,并且根据您正在使用的 RDBMS,整个子查询。还有一些查询可能在语法上是正确的,但仍然是非法的。

覆盖这个的单个正则表达式将 (a) 非常大并且 (b) 可能无法覆盖所有情况。您不仅真的不想这样做,而且可能根本不可能。

【讨论】:

【参考方案6】:

正如已经建议的那样,正则表达式是错误的工具,您真正需要的是 SQL 解析器。我不知道任何 .Net SQL 解析器,但我确信 Google 搜索会出现一些。

【讨论】:

【参考方案7】:

您可能想看看Subsonic。它旨在为您生成一个数据层,并让您使用对象来构建您的 where 子句。

【讨论】:

以上是关于SQL WHERE 子句的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

mysql查询的where子句中的正则表达式或替换函数

使 SQL Server 中的正则表达式搜索更高效

如何比较 SQL where 条件中的两个逻辑表达式? [关闭]

MySql学习笔记 —— 正则表达式的使用

10like子句

java:正则表达式检查SQL WHERE条件语句防止注入攻击和常量表达式