dynamic创buildSQL Where子句,不打开SQL注入

我写了这一点的VBA代码,根据用户select的字段数量和从XL电子表格中读取的值dynamic地创build一个SQL查询。 它基本上只是将“FIELD_VARIABLE = VALUE_VARIABLE OR”添加到where子句,然后在循环结束后删除最后的OR。

它适用于我希望添加的N个字段,但是我担心的是安全问题,因为我认为我可以将DROP TABLE Projects或其他恶意代码放入程序正在读取FIELD_VARIABLES的电子表格中。 在较小程度上,因为查询是不同的,每次执行path必须不同,这可能会减慢执行时间。

我正在考虑查看参数化查询或T-SQL来改善这一点。 希望你们中的一个聪明的人可以指点我在正确的方向,然后我浪费太多时间在这个。 这里是相关的VBA代码:

'---loop through array of search fields and search values using the same index '---since the arrays sizes will always be the same and create where filters dynamically i = 1 For i = LBound(sLookupFields) To UBound(sLookupFields) Set rngLookup = wsLookupSrc.cells(counter, lLookupCols(i)) '---clear where from last iteration through loop SQLWhereDynamic = "" SQLWhereDynamic = SQLWhereDynamic & " p." & sLookupFields(i) & " = '" + CStr(rngLookup.Value) & "' OR" Next i '---remove extra ' OR' SQLWhereDynamic = Left(SQLWhereDynamic, (Len(SQLWhereDynamic) - 3)) SQLValue = wsLookupSrc.cells(counter, lLookupCols(1)).Value SQLWhereDefault = "WHERE p.ClientId = " + CStr(iClientId) + "" SQLQuery = SQLSelect + SQLWhereDefault + " AND (" + SQLWhereDynamic + ");" 

我相信,在WHERE子句中使用WHERE子句中的值可能会使得WHERE子句中的字段名称成为一个参数(因此dynamic和安全的注入)是不可能的。 然而…

这是我将如何做到这一点。 假设您有一个包含所有可能字段的Excel范围,为您要search的字段填充的search值以及数据types(稍后将在代码中使用)。 以下示例显示了正在search的两个字段

 Field Value DataType Sequence 131 CustomerID 200 InvoiceNumber 200 OrderNumber 200 InvoiceDate 8/14/2015 7 Item DS2 200 Location 200 ExportFile 200 DateImported 7 OnHold 11 

用户填写第2列。代码构buildsqlstring

 Sub MakeSQL() Dim aSql(1 To 4) As String Dim aWhere() As String Dim vaFields As Variant Dim lWhereCnt As Long Dim lCnt As Long, i As Long Dim cn As ADODB.Connection Dim cmd As ADODB.Command Dim pm As ADODB.Parameter 'Skip number three until later aSql(1) = "SELECT *" aSql(2) = "FROM dbo.InvoiceLine" aSql(4) = "ORDER BY InvoiceNumber DESC;" 'Grab all the search criteria vaFields = Sheet1.Range("A2:C11").Value 'Set up the connection Set cn = New ADODB.Connection cn.Open sConn Set cmd = New ADODB.Command Set cmd.ActiveConnection = cn 'Count how many criteria where filled in 'You could Redim Preserve your aWhere() also On Error Resume Next lWhereCnt = Sheet1.Range("B2:B11").SpecialCells(xlCellTypeConstants).Count On Error GoTo 0 'If there's at least one If lWhereCnt >= 1 Then ReDim aWhere(1 To lWhereCnt) 'Fill in an array and create parameters For i = LBound(vaFields, 1) To UBound(vaFields, 1) If Len(vaFields(i, 2)) > 0 Then lCnt = lCnt + 1 'Put in the place holder aWhere(lCnt) = vaFields(i, 1) & "=?" 'column 3 holds the data type Set pm = cmd.CreateParameter(vaFields(i, 1) & "_p", vaFields(i, 3), adParamInput) pm.Value = vaFields(i, 2) 'Variable length data types (I only use varchar, you may use more) 'must have a size specified If vaFields(i, 3) = adVarChar Then pm.Size = Len(vaFields(i, 2)) cmd.Parameters.Append pm End If Next i 'Fill in the "where" section of your sql statement aSql(3) = "WHERE " & Join(aWhere, " OR ") End If cmd.CommandText = Join(aSql, Space(1)) 'Change this line to actually execute something Debug.Print cmd.CommandText For i = 0 To cmd.Parameters.Count - 1 Debug.Print , cmd.Parameters(i).Name, cmd.Parameters(i).Value Next i cn.Close Set cn = Nothing End Sub 

对于这个例子,string出来

 SELECT * FROM dbo.InvoiceLine WHERE InvoiceDate=? OR Item=? ORDER BY InvoiceNumber DESC; InvoiceDate_p 8/14/2015 Item_p DS2 
Interesting Posts