I'm trying to write a parameterized query in ASP Classic, and it's starting to feel like i'm beating my head against a wall. I'm getting the following error:
Must declare the scalar variable "#something".
I would swear that is what the hello line does, but maybe i'm missing something...
<% OPTION EXPLICIT %>
<!-- #include file="../common/adovbs.inc" -->
<%
Response.Buffer=false
dim conn,connectionString,cmd,sql,rs,parm
connectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Data Source=.\sqlexpress;Initial Catalog=stuff"
set conn = server.CreateObject("adodb.connection")
conn.Open(connectionString)
set cmd = server.CreateObject("adodb.command")
set cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
cmd.CommandText = "select #something"
cmd.NamedParameters = true
cmd.Prepared = true
set parm = cmd.CreateParameter("#something",advarchar,adParamInput,255,"Hello")
call cmd.Parameters.append(parm)
set rs = cmd.Execute
if not rs.eof then
Response.Write rs(0)
end if
%>
Here's some sample code from an MSDN Library article on preventing SQL injection attacks. I cannot find the original URL, but googling the title keywords (Preventing SQL Injections in ASP) should get you there quick enough. Hope this real-world example helps.
strCmd = "select title, description from books where author_name = ?"
Set objCommand.ActiveConnection = objConn
objCommand.CommandText = strCmd
objCommand.CommandType = adCmdText
Set param1 = objCommand.CreateParameter ("author", adWChar, adParamInput, 50)
param1.value = strAuthor
objCommand.Parameters.Append param1
Set objRS = objCommand.Execute()
See the following page on MSDN, near the bottom, referring specifically to named parameters.
MSDN example
ADO is going to expect question marks instead of actual parameter names in this case. Right now, the SQL "select #something" is not actually parameterized: it sees the "#something" as an (undeclared) SQL variable, not as a parameter. Change your CommandText line to this:
cmd.CommandText = "select ?"
And I think you will get the result you are looking for.
Good luck!
with server.createobject("adodb.command")
.activeConnection = application("connection_string")
.commandText = "update sometable set some_col=? where id=?"
.execute , array(some_value, the_id)
end with
I'm not sure what your query is intended to accomplish. I'm also not sure that parameters are allowed in the select list. MSDN used to have (many years ago, probably) a decent article on where parameters were allowed in a query, but I can't seem to find it now.
OTTOMH, your attempts to supply the parameter values to ADO look correct. Does your query execute if you do something like this?
SELECT 1 FROM sometable WHERE somefield = #something
Related
I am trying to make a Classic ASP/VBScript website more secure by making SQL statements parameterized.
I have the following function:
Function OpenUpdateableRS(strSQL)
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open strSQL, cnDZ, adOpenKeyset, adLockPessimistic, adCmdText
Set OpenUpdateableRS = rs
Set rs = Nothing
End Function
I intend to convert it to something like:
Function SecureOpenUpdateableRS(strSQL, strParam1, strParam2)
Dim rs
Dim cmdOB
Set cmdOB = Server.CreateObject("ADODB.CommandObject")
With cmdOB
.ActiveConnection = cnDZ
.CommandText = strSQL
.Parameters(0).value = strParam1
.Parameters(0).value = strParam2
End With
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open cmdOB.Execute, , adOpenKeyset, adLockPessimistic
Set SecureOpenUpdateableRS = rs
Set rs = Nothing
End Function
When I call the function with:
Set rs = SecureOpenUpdateableRS("SELECT CustID, LastActive, LoggedIn, SessionID FROM tblLogins WHERE EMail = ? AND PWord = ?", strEMail, strPassword)
I get a "500 - Internal Server Error" which is probably because I disabled debugging on the server.
Any ideas on how I could make the original function more secure without breaking it?
You'll have to create the parameters and append them to the command's parameter collection. Just assigning the values to (the same!) parameter can't possibly work. Google for a sample; perhaps this VB! sample will get you started.
Added:
I can think of two strategies to derive the parameter types:
If you pass the correct/maximally specified parameter values to the function you can map VarType(value) constants to parameter type constants
If you do a SELECT based on the fieldnames in the command text, you can map the recordset's field .Types to parameter type constants
It won't be trivial to get this right for all possible cases. I would pass pairs of value and desired type to the function.
I wasn't able to find a question/answer that covers this fully hence why I am asking. What I need to do is run a stored procedure that takes 1 parameter. It will return a set of results which I need to store in a record set. I plan to loop through this recordset later. I'm pretty inexperienced when it comes to older asp, but here is what I have to far:
dim myConn
Set myConn = Server.CreateObject("ADODB.Connection")
myConn.Open = ("DSN=example-dsn;SERVER=example-server;DATABASE=example-db;UID=user;PWD=pass;")
dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
With oStoredProc
.ActiveConnection = myConn
.CommandType = adCmdStoredProc
.CommandText = "myStoredProcedure"
.Parameters.Append(.CreateParameter("#PARAM1", ADODB.adInteger, ADODB.adParamInput, 10, 2012))
Dim rs : Set rs = .Execute()
End With
// Will loop through it here.
My guess is that I'm not setting up the recordset right, but like I said, I'm not really sure. If anyone can point me in the right direction I'd appreciate it!
You will want to make sure your result set is the correct object
set rs = Server.CreateObject("ADODB.Recordset")
Then you will use the open method I think it works something like this:
rs.Open oStoredProc
Then use the other members of the Record Set object to loop through the results.
Alright there were a few things I was doing wrong but here is what ended up working for me. First off it turns out I didn't need a parameter passed in, but that was not the problem anyway. One of the main issues what that 'adCmdStoredProc' wasn't recognized, which is odd because I've seen it used everywhere else, but replacing it with it's corresponding value, 4, did work.
dim myConn, cmd
Set myConn = Server.CreateObject("ADODB.Connection")
myConn.Open = ("DSN=[BLAH];SERVER=[SERVER];DATABASE=[BLAH];UID=[User];PWD=[Pass];")
dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
oStoredProc.CommandType = 4
oStoredProc.CommandText = "StoredProcedureName"
oStoredProc.ActiveConnection = myConn
// Add parameters here if needed.
Dim rs
Set rs = oStoredProc.Execute()
// I Loop through here
rs.Close
myConn.Close
Set rs = Nothing
Set oStoredProc = Nothing
Set myConn = Nothing
I hope this helps if anyone else needs it.
Dim rsStk As New ADODB.Recordset
Set rsStk = cnnPck.Execute("SP_JOB_ALL '" & Trim(te_Item) & "'")
Set Recordset= CONNECTION .Execute()
This one is simple way to do this thing
I know it is a common error, but I still can't solve it myself.
What I am trying to do is I have a SELECT item called status that allow the user to choose their employment status, I want to simply get the result and update the user_table(access file) status cell.
Any reply will be greatly appreciated!
The Code is below:
<!--#include file="../conn/conn.asp"-->
<%
id=request.QueryString("id")
status=request.Form("status")
sql="select * from user_table where id="&id
set rs=conn.execute(sql)
sql="update user_table set Status='"+status+"' where id="&id
'response.Write sql
conn.execute(sql)
conn.close
response.Write "<script>alert('Change Sucessful!');</script>"
set conn=nothing
response.end()
%>
I think you may be having a problem with conn.execute(sql) as well as response.end()
To fix it, you need to do either:
conn.execute sql
or
Call conn.execute(sql)
But, yeah, you should follow other comments posted as your technique has security issues. You should consider changing it to use parameters:
<!--#include file="../conn/conn.asp"-->
<%
id = request.QueryString("id")
status = request.Form("status")
sql = "select * from user_table where id = #id"
Set cmd = CreateObject("ADODB.Command")
cmd.CommandText = sql
Set cmd.ActiveConnection = conn
cmd.Prepared = True
cmd.Parameters.Refresh
cmd.Parameters("#id") = id
Set rs = cmd.Execute
Set rs = nothing
Set cmd = nothing
sql = "update user_table set status = #status where id = #id"
Set cmd = CreateObject("ADODB.Command")
cmd.CommandText = sql
Set cmd.ActiveConnection = conn
cmd.Prepared = True
cmd.Parameters.Refresh
cmd.Parameters("#status") = status
cmd.Parameters("#id") = id
Set rs = cmd.Execute
Set rs = nothing
Set cmd = nothing
response.Write "<script>alert('Change Sucessful!');</script>"
Set conn = nothing
response.end
%>
I'm guessing conn.asp leaves conn open? otherwise you need to open it. Also, what shows when you uncomment the response.write sql line?
And, you are definitely opening yourself to hackers. You need to 'clean' anything that comes from a request.form or request.querystring (with at the very least, a replace(..., "'", "''"), or much better, use stored procedures instead of straight sql
I'm using SQL Server 2005 with classic ASP and on a form repost (I post back to the same page), I replace each text field as follows:
course = trim(replace(request("course"),"'","''"))\
The problem with this is if I have to repost the form multiple times in case of validation errors, the tick marks I replace multiply.
Is there another way to safely vet the string fields without doing this kind of replace?
you better use a parametrized query:
dim cmd : set cmd = server.createObject("ADODB.Command")
dim param
dim sql : sql = "INSERT INTO table(course) VALUES (?)"
cmd.ActiveConnection = yourDBconnection
cmd.CommandType = adCmdText
set param = cmd.CreateParameter("course", adVarChar, , 20, request("course"))
cmd.Parameters.Append param
cmd.CommandText = sql
cmd.Execute
so you are completely safe with sql injection
Only replace the ' for use in the sql string. (which you should better do with parameterized queries..)
The easiest way would be to only do the SQL escaping when you're actually inserting into the database:
course = trim(request("course"))
Make a SafeSQL function:
function SafeSQL(TempStr)
SafeSQL = Replace(TempStr,"'","''")
end function
Then, when you're inserting:
"INSERT INTO table(course) VALUES ('" & SafeSQL(course) & "')"
Disclaimer: I only have a working knowledge of ASP, I don't really know the best practices.
you can do this
course = trim(replace(request("course"),"'","&apos ;"))
When ever I try to access the RecordCount property, I always get a return value of -1. Below is my sample code.
Set oConn = Server.CreateObject ("ADODB.Connection")
oConn.Open Application("strConnectstring")
Set rs = Server.CreateObject ("ADODB.Recordset")
rs.ActiveConnection = oConn
SQL = "Publications_PicoSearchListing"
set rs = oConn.execute(SQL)
I'm not sure if I'm doing forwardCursor or dynamic cursors, or if the provider even supports the RecordCount property. How do I check if the provider supports RecordCount property or if I'm using either forwardCursor or dynamic cursors.
Any help would be appreciated.
Thank You
Recordcount is not supported with the default forward-only cursor.
you must add extra parameters to the open command
rs.open sql,conn,1,1
That should let you have access to rs.recordcount.
But paging is best done by using the Recordset.GetRows() + Recordset.Move() method.
http://databases.aspfaq.com/database/how-do-i-page-through-a-recordset.html
(scroll down to the bold "Recordset.GetRows() + Recordset.Move()" this is fastest way without using stored procedures)
Please note: unless you move to the end of the recordset there is no guarantee that the RecordCount will have been populated. The standard pattern to to iterate over each row in the recordset using While Not rs.EOF. In all the VBA code I've ever written, I have never relied on checking rs.RecordCount
Rather than checking the cursor type, you can set it. For example:
Set conn=Server.CreateObject("ADODB.Connection")
conn.Provider="Microsoft.Jet.OLEDB.4.0"
conn.Open(Server.Mappath("northwind.mdb"))
set rs = Server.CreateObject("ADODB.recordset")
sql="SELECT * FROM Customers"
rs.CursorLocation = adUseClient
rs.CursorType = adOpenStatic
rs.LockType = adLockBatchOptimistic
rs.Open sql, conn
If all you want is the count, why not emit a "SELECT Count(*) From Publications_PicoSearchListing"
Of Interest?: Understanding ADO's Default Cursor Type
Another alternative to get the RecordCount is to execute:
rs.MoveLast
rs.MoveFirst
and then check the RecordCount, and even then I seem to remember some cursor types aren't guaranteed (but memory hazy on this).
Also note: Don't use the MoveLast/MoveFirst unless you really need to: this will be slow with a large recordset or a recordset drawn across a network. Instead use the Count(*) technique.
For paging you can use the recordset.PageSize and recordset.AbsolutePage like this
Set rs = Server.CreateObject("ADODB.Recordset")
' make recordset use adUSEclient ( client side cursor)'
rs.CursorLocation = 3
' make recordset use the adOpenStatic cursor ( scrollable )'
rs.CursorType = 3
rs.PageSize = RecordsPerPage
rs.Open sql, conn
' go to selected page'
if not rs.EOF and not rs.BOF then
rs.AbsolutePage = page_you_want_to_go
end if
you then have access to recordset.PageCount to know the number of pages returned..