用于SQL WHERE子句的正则表达式

时间:2008-10-15 13:43:09

标签: sql ajax regex

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

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

在提交给SQL Server之前,你能提出一个正则表达式来验证该子句吗?

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

7 个答案:

答案 0 :(得分:16)

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

作为可能出现问题的一个例子,请考虑一下:

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

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

答案 1 :(得分:6)

你没有建立

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

你建立

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

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

答案 2 :(得分:2)

我想稍微扩展吉米的答案。

LASTNAME LIKE 'Pep%' 

那只是 EVIL 。永远不要这样做。 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),但几乎每个现代平台都有一些你应该使用的参数化查询/预备语句功能。

答案 3 :(得分:2)

其他几位评论者已经提到了允许用户输入来确定SQL语法是一个坏主意并创建SQL注入漏洞的观点。

请注意评论者在此意见中是一致的,并且StackOverflow的“声誉”总数超过14,000!

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

此上下文中的“常规”表示表达式可以匹配某类输入语言,也可以用deterministic finite state-machine表示(类似于流程图)。

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

答案 4 :(得分:0)

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

要覆盖这一点的单个正则表达式将(a)非常大,(b)可能不涵盖所有情况。你不仅真的不想这样做,而且甚至可能都不可能。

答案 5 :(得分:0)

正如已经提到的,正则表达式是工作的错误工具,你真正需要的是一个SQL解析器。我不知道任何.Net SQL解析器,但我确信谷歌搜索会出现一些。

答案 6 :(得分:0)

您可能需要查看Subsonic。它旨在为您生成数据层,并允许您使用对象来构建where子句。