ASP Classic - Recordset Object vs. Command Object - stored-procedures

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

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

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) !

Related

SqlParameter vs array of object

I have a stored procedure that has many parameters and I've been using the following to return the results:
db.Database.SqlQuery<GetListCamera_Result>("Camera.sp_get_list_camera #room_name, #disk_status,
#signal_loss_reason, #department_id , #sortColumnName, #sortDirection, #start, #length",
new SqlParameter("room_name", room_name),
new SqlParameter("disk_status", disk_status),
new SqlParameter("department_id", department),
new SqlParameter("signal_loss_reason", reason),
new SqlParameter("sortColumnName", sortColumnName),
new SqlParameter("sortDirection", sortDirection),
new SqlParameter("start", start),
new SqlParameter("length", length)).ToList();
I saw one of my senior using these much more cleaner than mine:
db.Database.SqlQuery<GetLiquidbooks_Result>("sp_get_liquidbooks {0}, {1}, {2}, {3}, {4}",
new object[] { LiquidCode, LibID, LocPrefix, LocID, UserID }).ToList();
What are the differences and is there anything I need to be aware of if I'm switching to his
I think yours is a much safer way. However, if you'd like to make it simpler, you can refer to this article, you don't have to initialize a SqlParameter instance, but the #p1 #p2 syntax is still essential. In the first section of the article, it also mentions that this care should be taken.
AFAIK, SqlQuery doesn't prevent SQL Injection, which means if I pass the DROP command into your second sample, the table may be deleted permanently. Therefore, the one which the senior wrote might expose potential security risks, you should make sure that you use parameters in your query in the correct way to guard against such attacks.
About the second sample, consider using ObjectContext.ExecuteStoreQuery<T>(), it allows you to pass the query string with {0} {1} syntax and object array as the parameter into the method. This method actually invokes CreateStoreCommand which transforms your query and objects into a parameterized query. But SqlQuery seems not.
FYI:
ExecuteStoreQuery source code - You can take a look at this method to get deep into how it works.
SqlQuery source code - As aforementioned, I rechecked the source code, and I couldn't find any codes that help to turn it into parameterized SQL

Error selecting from large data table causing time out in EF + code first

I am using EF code first model to get the data from data base table in which i have 400,000 records.
But when i use the LINQ query something like:
var urer = context.UserEntity.Where(c => c.FirstName.Contains('s'));
The above statement gives me all the user to whose first name contains 's'. But since this is a huge data base table, it is giving me the following error:
An existing connection was forcibly closed by the remote host
Please suggest me the best way to do it. I am assigning this data to gridview. I am thinking to get the first 500 each time. Is there any way to do it from EF side, so that i won't need to do it in sql.
Thanks
1.add index on your column
2. increase timeout connection
You can create Store procedure
USE LINQ call Store procedure
LINQ to SQL (Part 6 - Retrieving Data Using Stored Procedures)
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx
See this answer as well
Calling a SQL Server stored procedure with linq service through c#
Get rid of EF
set key in web.config common key for timeout replace 600
try
{
conn.Open();
mySqlCommand.Connection = conn;
mySqlCommand.CommandTimeout=600;

Setting a var equal to SQL code

I have a school PAT project where I need to do something extra, and in order to do so I need to do the following (I am using delphi 7 and ms access):
I want to set sql code = to a variable in order to use the var for something like a calculation.
I am thinking something like this:
s(var):=ADOQuery1.SQL.Text:='SELECT Birthdate where username = '+edtUsername.text;
So basically I want to set a specific ms access cell = to a var in delphi.
You trying to do too much in one line.
You set the SQL.Text
Then run the Query.
Then read one line into your variable.
Furthermore never inject parameters directly into a query; this leads to SQL injection vulnerabilities. Use parameters instead.
In pseudo code:
ADOQuery1.SQL.Text:='SELECT Birthdate where username = :name';
ADOQuery1.Parameters.ParamByName('name'):= aname; <<-- save way to use parameters.
ADOQuery1.RunQuery;
var1:= ADOQuery1.FieldByName('BirthDate').AsDate;
Obviously you need to fix the SQL statement, because it is incomplete and tweak the code a little. But I'll leave that as an exercise.
Here's the documentation for TADOQuery: http://docwiki.embarcadero.com/Libraries/XE5/en/Data.Win.ADODB.TADOQuery

Incorrect syntax near ',' in F# typeprovider insert query with datacontext

I am trying to insert data through F# typeprovider datacontext. I have a table in database dbo.tbl_Location, want to insert data with following simple query.
let InsertTaskDetails() =
dbSchema.GetDataContext().DataContext.ExecuteCommand("Insert into dbo.tbl_Location (LocationId,Location) Values (11, 'india')")
dbSchema.GetDataContext().DataContext.SubmitChanges()
But I am getting error:
Incorrect syntax near ','
I can't understand what's happening when I run the same query in SQL Server 2008
Insert into dbo.tbl_Location (LocationId,Location) Values (11, 'india')
It works fine. LocationId is of int type and Location is of string type.
If somebody has ideas about it please tell me where I am missing the things.
Craig is right. If you're calling ExecuteCommand on an Entity Framework DataContext, you can't pass T-SQL in, because the Entity Framework DataContext only understands Entity SQL.
Also, when you're directly executing a command like you are, there's no need to call SubmitChanges - which is a good thing, because you're calling SubmitChanges on a different instance of the data context than you called ExecuteCommand on. GetDataContext creates an instance each time you call it. If you wanted to do the insert the idiomatic Entity Framework Type Provider Way, it would look more like this:
type tbl_Location = dbSchema.ServiceTypes.tbl_Location
let insertTaskDetails () =
use db = dbSchema.GetDataContext() // it's disposable!
db.tbl_Locations.AddObject(tbl_Location(LocationId=11, Location="india"))
db.DataContext.SaveChanges() |> ignore

Subsonic 3.0.0.3 not generating parameters for stored procedures

I have a SQL Server 2008 database with a bunch of stored procedures. When I use the ActiveRecord Template provided with Subsonic 3.0.0.3, it generates methods for all of my stored procedures, but they do not have any parameters. I am dbo on the server and can execute the stored procedures with no issue from Management studio.
Example Stored Procedure
CREATE PROCEDURE [dbo].[prc_Sample]
#FileName VARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF EXISTS ( SELECT * FROM Sample WHERE FileName = #FileName )
BEGIN
RETURN -1
END
RETURN 0
END
Sample Generated Method
public StoredProcedure prc_Sample(){
StoredProcedure sp=new StoredProcedure("prc_Sample",this.Provider);
return sp;
}
If I check SQLServer.ttinclude, I can see that all of methods for getting stored procedures are there, but for some reason they are not generating. And this isn't an an issue of having underscores in the stored procedure names - this is broken with and without underscores.
Any ideas or anyone know how to debug a template file?
I had the same issue, and I had to tweak the SQLServer.ttinclude to get it working. Inside that file find the GetSPParams() method and change one line:
from
string[] restrictions = new string[4] { DatabaseName, null, spName, null };
to
string[] restrictions = new string[3] { null, null, spName };
.
BlackMael's answer has a helpful link that helped me figure out how to debug and step through the template code.
Now I'm not 100% sure yet that my change is a good one (there may be some adverse effects). I just haven't had a chance to test it thoroughly and need to read up some more on Restrictions as they pertain to the GetSchema() method. But for now, that solved my problem and I can successfully pass in my stored proc parameter.
Update: This may have something to do with the fact that my DB file is embedded in the VS solutin in App_Data. Perhaps this works better out of the box with a stand-alone SQL Server instance.
To debug a T4 template file...
T4 Tutorial: Debugging Code Generation Files
Using the project in the SubSonic-30-Templates that points to an instance of Northwind in SqlExpress I added the stored procedure above. Re-generated the StoredProcedures.tt and it happily created...
public StoredProcedure prc_Sample(string FileName){
StoredProcedure sp=new StoredProcedure("prc_Sample",this.Provider);
sp.Command.AddParameter("FileName",FileName,DbType.AnsiString);
return sp;
}
Though I use the latest and greatest build, I've not noticed issues with parameters missing.
Can you post your Settings.ttinclude and possibly SqlServer.ttinclude file? Or maybe a link to them? The StoredProcedures.tt may be good too.
Another possible cause of this is that the Database has no dbo assigned.
Similar to Kon M's answer I changed the line in SQLServer.tt to:
string[] restrictions = new string[4] { null, null, spName, null };
This resolved the problem for me.

Resources