摘要:Web应用程序具有动态生成的SQL语句,因为它每次都可以包含可变数量的列,因为该表可以添加新列。
需要知道如何使用存储过程或预准备语句来执行此操作,以便SQL注入安全。
明细:我正在使用特定的网络应用,其唯一目的是将请求服务器变量集合记录到表中。每个请求1行,每个服务器变量1列。由于服务器变量的数量可以改变,例如果请求有自定义标题等,要处理此问题,它会检查列,必要时添加新列:
'1 - ensure table columns are adequete and add new cols if necessary
Set oSchema = Server.CreateObject("Scripting.Dictionary")
Set oRsCols = oConn.Execute("SELECT ORDINAL_POSITION, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'REQUESTS'")
Do While Not oRsCols.EOF
oSchema.Add oRsCols("COLUMN_NAME").value, oRsCols("ORDINAL_POSITION").value 'add dictionary row
oRsCols.MoveNext
Loop
Set oRsCols = Nothing
'grab this request's server vars collection, and if a new one is found, add a column to table for it
For Each serverVariable In Request.ServerVariables
If len(oSchema(servervariable)) = 0 Then 'a new variable in the collection
oConn.execute("ALTER TABLE REQUESTS ADD " & serverVariable & " VARCHAR(8000) NULL")
End If
Next
然后动态编译SQL语句,例如INSERT INTO TABLE (...) VALUES (...)
如下:
'2 - now that the table is good, compile the insert statement
sColString = ""
sValuesString = ""
For Each serverVariable In Request.ServerVariables
sCurrentVariable = serverVariable
sCurrentVariableValue = request.ServerVariables(serverVariable)
sColString = sColString & sCurrentVariable & ", "
If checkNull(sCurrentVariableValue) Then
sValuesString = sValuesString & "NULL, "
Else
sValuesString = sValuesString & "'" & sCurrentVariableValue & "'" & ", "
End If
Next
'handle trailing commas
sColString = replace(sColstring & "!@#", ", !@#", "") & ", DB_INSERT_DATE"
sValuesString = replace(sValuesString & "!@#", ", !@#", "") & ", GETDATE()"
oConn.execute("INSERT INTO REQUESTS (ASP_SESSION_ID, " & sColString & ") OUTPUT INSERTED.ID VALUES (" & nvl(Session.SessionID, "NULL") & ", " & sValuesString & ")")
列和值在Web应用程序中即时编译(因为列数可能每次都有所不同,列列表可能会增长,例如,如果遇到新的自定义服务器变量)。
这是SQL的唯一类型我无法弄清楚如何正确转换为存储过程或参数化查询(同样,因为列和列计数未知并且因为不同的请求可以生成不同的服务器而有所不同变量,例如自定义服务器变量,如果找到新的服务器变量,app会向表中添加一个新列。然后循环遍历每个变量并编译一个sql语句。)
我非常担心SQL注入,因为这种方法容易受到攻击。我经常看到这样的HTTP_USER_AGENT值(这里没有成功,但仍然......):
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0';declare @b cursor;declare @s varchar(8000);declare @w varchar(99);set @b=cursor for select DB_NAME() union select name from sys.databases where (has_dbaccess(name)!=0) and name not in ('master','tempdb','model','msdb',DB_NAME());open @b;fetch next from @b into @w;while @@FETCH_STATUS=0 begin set @s='begin try use '+@w+';declare @c cursor;declare @d varchar(4000);set @c=cursor for select ''update [''+TABLE_NAME+''] set [''+COLUMN_NAME+'']=[''+COLUMN_NAME+'']+case ABS(CHECKSUM(NewId()))%10 when 0 then ''''<div style="display:none">blah blah spam <a href="http://www.spam-example.com">''''+case ABS(CHECKSUM(NewId()))%3 when 0 then ''''some spam'''' when 1 then ''''read'''' else ''''some spam'''' end +''''</a> blah blah</div>'''' else '''''''' end'' FROM sysindexes AS i INNER JOIN sysobjects AS o ON i.id=o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME=TABLE_NAME WHERE(indid in (0,1)) and DATA_TYPE like ''%varchar'' and(CHARACTER_MAXIMUM_LENGTH in (2147483647,-1));open @c;fetch next from @c into @d;while @@FETCH_STATUS=0 begin exec (@d);fetch next from @c into @d;end;close @c end try begin catch end catch';exec (@s);fetch next from @b into @w;end;close @b--
如何使用注入安全方法插入行来实现此目的?