在vb脚本中,我有一条select语句,我试图将长度不确定的字符串值传递给SQL in运算符,以下代码有效,但允许进行SQL注入。
我正在寻找一种使用ADO createParameter方法的方法。我认为我尝试过的不同方法都陷入了我的数据类型(adVarChar,adLongChar,adLongWChar)
Dim studentid studentid = GetRequestParam("studentid")Dim rsGetData, dbCommandSet dbCommand = Server.CreateObject("ADODB.Command") Set rsGetData = Server.CreateObject("ADODB.Recordset") dbCommand.CommandType = adCmdText dbCommand.ActiveConnection = dbConn dbCommand.CommandText = "SELECT * FROM students WHERE studentID in (" & studentid & ")"Set rsGetData = dbCommand.Execute()
我试过了
Call addParameter(dbCommand, "studentID", adVarChar, adParamInput, Nothing, studentid)
这给了我这个错误ADODB.Parameters错误'800a0e7c'添加参数(studentID)=('SID0001','SID0010')时出现问题:参数对象定义不正确。提供的信息不一致或不完整。
我也尝试过
Call addParameter(dbCommand, "studentID", adLongVarChar, adParamInput, Nothing, studentid)
和
Dim studentid studentid = GetRequestParam("studentid")Dim slength slength = Len(studentid)response.write(slength)Dim rsGetData, dbCommandSet dbCommand = Server.CreateObject("ADODB.Command") Set rsGetData = Server.CreateObject("ADODB.Recordset") dbCommand.CommandType = adCmdText dbCommand.ActiveConnection = dbConn dbCommand.CommandText = "SELECT * FROM students WHERE studentID in (?)" Call addParameter(dbCommand, "studentID", adVarChar, adParamInput, slength, studentid)Set rsGetData = dbCommand.Execute()
这两个选项均不执行任何操作...没有错误消息,并且未执行SQL。
附加信息:
通过HTML表单文本区域输入了studentid。该设计应能够让用户输入学生ID的列表(最多1000行)并在这些学生资料上执行操作。在上一个asp的javascript中,我有一个函数来接收列表并将其更改为逗号分隔的列表,并在列表中的每个元素周围加上''。
经典ASP对此没有很好的支持。您需要使用此处讨论的替代方法之一:
那篇文章有点长,但是用一种很好的方式:很多人认为这是该主题的标准著作。
碰巧的是,我的首选选项未包含在该文章中。我想做的是为列表中的每个项目使用一个保留表,以便每个项目都使用ajax请求在用户选择或取消选择时将其从保留表中插入或删除。然后,我加入该表作为我的列表,这样您就可以得到如下内容:
SELECT s.* FROM students s INNER JOIN studentSelections ss on s.StudentID = ss.StudentIDWHERE ss.SessionKey = ?
您的addParameter()
职能是什么?我在您的代码的任何地方都看不到。
您应该能够像这样创建和添加字符串参数:
With dbCommand.Parameters.Append .CreateParameter(, vbString, , Len(studentid), studentid)End With
(这里的小技巧。vbString
与的价值相同adBSTR
。您会发现,VarType
所有VB“类型”的都有匹配的ADO对应项。)
Type VarType (VBScript)DataTypeEnum (ADO)Value--------------------------------------------------IntegervbInteger adSmallInt, 2-byte2Long vbLongadInteger, 4-byte 3Single vbSingleadSingle4Double vbDoubleadDouble5Currency vbCurrencyadCurrency6Date vbDateadDate7String vbStringadBSTR8Object vbObjectadIDispatch 9ErrorvbError adError10BooleanvbBoolean adBoolean11VariantvbVariant adVariant12Byte vbByteadUnsignedTinyInt17
编辑:看起来乔尔为您提供了一个很好的解决方案。我没有意识到IN
与ADO参数化查询不兼容。我认为类似以下内容的方法可能会起作用,但您可能不想(可能)使用1000个ID。
' Create array from student IDs entered... a = Split(studentid, ",") ' Construct string containing proper number of param placeholders. Remove final comma.strParams = Replace(String(UBound(a) - 1, "?"), "?", "?,")strParams = Left(strParams, Len(strParams) - 1)With dbCommand.CommandText = "select * from students where studentID in (" & strParams & ")" Set rsGetData = .Execute(, a)End With
阅读了乔尔(Joel)提供的文章以及All Blond提供的答案之后,这就是最终为我工作的解决方案。
Dim studentid studentid = GetRequestParam("studentid")Dim splitStudentid, x splitStudentid = Split(studentid,",")for x=0 to Ubound(splitStudentid)Dim rsGetData, dbCommand, originSIDSet dbCommand = Server.CreateObject("ADODB.Command")Set rsGetData = Server.CreateObject("ADODB.Recordset")dbCommand.CommandType = adCmdText dbCommand.ActiveConnection = dbConn dbCommand.CommandText = "SELECT * FROM students WHERE studentID=?"Call addParameter(dbCommand, "studentID", adVarChar, adParamInput, 35, splitStudentid(x))Set rsGetData = dbCommand.Execute()If (NOT rsGetData.EOF) Then originSID = rsGetData.Fields(0) //additional codeEnd Ifnext
我发现在我的代码中没有优雅的方式使用“ in”运算符。我也决定反对存储过程,因为这是一个简单的查询,尽管我同意
我还意识到addParameter是我公司内部使用的功能,因此下面是一个可行的附加解决方案,但不是我公司的偏好。
Dim studentid studentid = GetRequestParam("studentid")Dim splitStudentid, x splitStudentid = Split(studentid,",")for x=0 to Ubound(splitStudentid)Dim rsGetData, dbCommand, originSIDSet dbCommand = Server.CreateObject("ADODB.Command")Set rsGetData = Server.CreateObject("ADODB.Recordset")dbCommand.CommandType = adCmdText dbCommand.ActiveConnection = dbConn dbCommand.CommandText = "SELECT * FROM students WHERE studentID=?"Set rsGetData = dbCommand.Execute(, Array(splitStudentid(x)))If (NOT rsGetData.EOF) Then originSID = rsGetData.Fields(0) //additional codeEnd Ifnext
IN
与参数化查询一起使用并不困难这并不像您想的那样困难,adCmdText
查询只需要查询中的占位符以匹配参数数量及其顺序位置即可,并且可以与您传递到IN
语句中的任意数量的参数一起使用。
这是在SQL Server中使用AdventureWorks示例数据库的快速示例。我们使用Array
来存储Person.Contact
要过滤的每条记录的ID,IN
然后在执行之前根据该数组动态构建参数ADODB.Command
。
注意:数组的来源并不重要,它可以是一个字符串列表,该字符串列表可以
Split()
进入Array
或只是一个Array()
调用(如本示例中使用的那样)。
<%Option explicit%><!-- #include virtual = "/config/data.asp" --><%Dim cmd, rs, sql, data, rows, row'Our example parameters as an Array for the IN statement.Dim ids: ids = Array(2, 5, 10)Dim id sql = ""sql = sql & "SELECT [FirstName], [LastName] " & vbCrLf sql = sql & "FROM Person.Contact " & vbCrLf sql = sql & "WHERE [ContactId] IN (?, ?, ?) " & vbCrLf sql = sql & "ORDER BY [LastName], [FirstName]" & vbCrLfSet cmd = Server.CreateObject("ADODB.Command")With cmd.ActiveConnection = conn_string.CommandType = adCmdText.CommandText = SQL'Loop through the Array and append the required parameters. For Each id in idsCall .Parameters.Append(.CreateParameter("@id" & id, adInteger, adParamInput, 4)) .Parameters("@id" & id).Value = idNext Set rs = .Execute() 'Output the Recordset to a 2-Dimensional Array If Not rs.EOF Then data = rs.GetRows() Call rs.Close()End WithSet cmd = NothingIf IsArray(data) Then rows = UBound(data, 2) For row = 0 To rowsCall Response.Write("<p>" & data(0, row) & " " & data(1, row) & "</p>" & vbCrLf) NextEnd If%>
输出:
<p>Catherine Abel</p><p>Pilar Ackerman</p><p>Ronald Adina</p>