views:

52

answers:

2

Hi

I am using ASP Classic and SQL Server 2000 to create dynamic websites.

I am a bit confused about when to use a recordset object and when to use a command object when querying the database.

I was told that if the stored procedure would be returning records from a SELCT statement then I should use a recordset, however if I am up updating or inserting then I should use a command object and pass all data as parameters to the stored procedure.

When using a recordset I often pass any required data like so:

rs.Source = "spTest "   & id

I alway validate the data that I am passing to make sure it is what I am expecting and cast it to its correct type.

I have since been told however that the above method leaves my code open to SQL Injection attacks and that I should always use a command object.

Is this correct?

Thanks

+2  A: 

Yes, that's right.

Imagine someone passing the string: '0; delete * from users;'

You query would then be:

spTest 0; delete * from users;

If you're lucky you won't have a users table. Personally, I would use the command object all the time for consistency. You can get everything you need from it.

Here is a quick example of how you might do it with the command object:

    Dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")

    With oStoredProc
        .ActiveConnection = oDBConnection
        .CommandType = adCmdStoredProc
        .CommandText = "up_procname"
        .Parameters.Append(.CreateParameter("@Param1", ADODB.adInteger, ADODB.adParamInput, 22, 11))
        .Parameters.Append(.CreateParameter("@Param2", ADODB.adInteger, ADODB.adParamOutput, 22, 12)

        Call .Execute()

        myVal = .Parameters("@Param2")
    End With

    Set oStoredProc = Nothing
James Wiseman
Thanks.Say that, like in the example that I gave, I know the parameter is going to be numeric and I have validated the input to make sure that it is. Would it be OK to use the recordset object as I described or should I use the command object regardless? I only ask as alot of the time it is only numerical values that I am passing through and it would save me alot of time if I didn't have to go through and change them all.Thanks
chester600
A: 

What you were told is correct indeed : you should always use commande objects to prevent SQL Injection. Using parameterized queries, you leave all the security and validation of parameters to the ADO layer (though you should still do your own proper validation), and you may even get some performance improvement (these parameterized queries are cached by SQL Server)

When you execute a command you have two options : either the SQL you execute returns rows (A SELECT Statement, or some stored procedures), then you have to use a recordset to store these rows, either it doesn't (UPDATES, DELETES, other procedures), then you juste execute the command and do not worry about recordsets.

Edit : just to make sure everything is clear for you, I used James Wiseman's code above and adapted it to your example :

Dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")

With oStoredProc
    .ActiveConnection = oDBConnection
    .CommandType = adCmdStoredProc
    .CommandText = "spTest ?"
    .Parameters.Append(.CreateParameter("id", ADODB.adInteger, ADODB.adParamInput, id, 11))
    Dim rs : Set rs = .Execute()
End With

Set oStoredProc = Nothing

Didn't test it, but should be ok :-)

Last but not least : even though you're pretty well protected now, don't forget that if you're using dynamic SQL inside your stored procedure you may still have an SQL Injection security hole (as soon as you're concatenating strings to create SQL you may be vulnerable I would say) !

Sébastien Nussbaumer
Thanks. So should I only ever use the recordset object in conjunction with the command obbject?I also assume that it is OK to use the recordset object when I am running a stored procedure that doesn't require any parameters to be passed to it?Thanks
chester600
In order to make thing simpler I would encourage you to always use the same method : just always use Recordsets with Command objects, and don't think about it anymore. You may have a little more to type sometimes, but this can be easily avoided with some helper functions you can write (you'll soon see which code is always repeated)
Sébastien Nussbaumer