Summary: Web app has a SQL statement that is dynamically generated because it can have a variable number of columns each time because the table can have new columns added.
Need to know how to do that using a stored procedure or prepared statement so that it is SQL injection safe.
Detail: I'm working with a specific web app which sole purpose is to log the request server variables collection to a table. 1 row per request, 1 column per server variable. Since count of server variables can change e.g. if request has a custom header, etc. To handle this, it checks columns, adds new one(s) if necessary:
'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
It then compiles the SQL statement dynamically e.g. INSERT INTO TABLE (...) VALUES (...)
as follows:
'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 & ")")
Columns and values are compiled on the fly in the web app (since the count of columns can vary each time, and column list can grow e.g. if a new custom server variable is encountered).
This is the only type of SQL I have not been able to figure out how to properly convert to a stored procedure or parameterized query (again, because columns and column counts are not known and vary e.g. since different requests can generate different server variables e.g. a custom server variable, the app adds a new column to the table if a new server variable is found. It then loops through each variable and compiles a sql statement.)
I am obvously worried about SQL injection, since this method is vulnerable. I often see HTTP_USER_AGENT values coming through like this (which didn't succeed here, but still...):
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--
How can I achieve this while having an injection-safe method of inserting the row?
Aucun commentaire:
Enregistrer un commentaire