在动态列名中阻止SQL注入

时间:2012-06-08 17:08:23

标签: .net sql vb.net postgresql sql-injection

我无法离开没有在我的系统的一部分中编写一些动态sql条件(使用Postgres)。

我的问题是如何最好地避免使用我目前使用的方法进行SQL注入。

编辑(推理):许多表中有许多列(一个数字增长(仅)并在其他地方维护)。我需要一种允许用户决定他们想要查询哪个(预定义)列的方法(如果需要,还可以应用字符串函数)。查询本身太复杂,用户无法自己编写,也无法访问数据库。有1000个用户有不同的要求,我需要保持尽可能灵活 - 我不应该重新访问代码,除非主要查询需要更改 - 此外,没有办法知道用户需要什么条件使用

对于某些大型SQL查询,我有对象(通过Web服务接收)生成条件(生成方法如下 - 它还不完美)。

_FieldName是用户可编辑的(参数名称是,但不需要),我担心它可能是攻击媒介。我在字段名称周围加上双引号(see quoted identifier)以尝试清理字符串,这样它就永远不会成为关键字。我也可以根据字段列表查找字段名称,但很难及时维护。

不幸的是,用户必须输入条件标准,我确定必须有更多我可以添加到sanatize方法?引用列名称是否安全? (我的有限测试似乎是这么认为的。)

一个示例构建条件是“AND upper(brandloaded.make)像'O%'和upper(brandloaded.make)不像'OTHERBRAND'”......

任何帮助或建议表示赞赏。

Public Function GetCondition() As String
   Dim sb As New Text.StringBuilder

   'put quote around the table name in an attempt to prevent some sql injection
   'http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html
   sb.AppendFormat(" {0} ""{1}"" ", _LogicOperator.ToString, _FieldName)

   Select Case _ConditionOperator
      Case ConditionOperatorOptions.Equals
          sb.Append(" = ")

      ...

   End Select

   sb.AppendFormat(" {0} ", Me.UniqueParameterName) 'for parameter

   Return Me.Sanitize(sb)

End Function

Private Function Sanitize(ByVal sb As Text.StringBuilder) As String

   'compare against a similar blacklist mentioned here: http://forums.asp.net/t/1254125.aspx

    sb.Replace(";", "")
    sb.Replace("'", "")
    sb.Replace("\", "")
    sb.Replace(Chr(8), "")

    Return sb.ToString

End Function

Public ReadOnly Property UniqueParameterName() As String
     Get
         Return String.Concat(":" _UniqueIdentifier)
     End Get
End Property

3 个答案:

答案 0 :(得分:6)

您可以从数据库中获取列名并进行比较以检查用户是否输入了有效的列名。

答案 1 :(得分:2)

SQL注入发生是因为用户输入的数据用于动态查询,而不进行参数化。不幸的是,在您的情况下,用户输入的数据无法进行参数化,解决方案是不让用户输入该数据。

可能的解决方法是使用可接受字符的白名单(不是黑名单)。但实际上,您应该看到获取fieldNames列表并验证用户输入(然后使用您的字符串版本,而不是来自用户的字符串)。

用户输入的数据总是令人怀疑,如果可能的话应该避免。

答案 2 :(得分:0)

您可以做的一件事是继续创建动态查询,但将这样的内容作为前缀:

"IF EXISTS(SELECT * FROM sys.columns where object_id=OBJECT_ID('mytable') and name = @dynamicName)
    SELECT * FROM mytable WHERE [" + dynamicName + "] = 'Whatever your test is.'"

是的,它使查询稍微贵一点,但是可以防止注入。