SQL Injection protection

M

Mr Beaton

Hey all,

I'm far from new to programming, neither ASP nor SQL. However, my SQL
knowhow is apparently wanting...

I have allways validated user input to pieces prior to integrating it into a
SQL statement, in order to avoid SQL Injection attacs. A colleague of mine
told me that binding my vars would make them SQL scalar, but I have been
left in the dark as to HOW... The web left me none the wiser, as well, so
here goes: Anyone got a brief example of binding vars in ASP to get me
started? I'll name my firstborn after the provider of such assistance... ;-)

Leif Beaton
 
B

Bob Barrows [MVP]

Mr said:
Hey all,

I'm far from new to programming, neither ASP nor SQL. However, my SQL
knowhow is apparently wanting...

I have allways validated user input to pieces prior to integrating it
into a SQL statement, in order to avoid SQL Injection attacs. A
colleague of mine told me that binding my vars would make them SQL
scalar, but I have been left in the dark as to HOW... The web left me
none the wiser, as well, so here goes: Anyone got a brief example of
binding vars in ASP to get me started?

I suspect your colleague was talking about using parameters. See either this

If you are using stored procedures (recommended):
http://tinyurl.com/jyy0

or this:
http://groups-beta.google.com/group/microsoft.public.inetserver.asp.db/msg/72e36562fee7804e
I'll name my firstborn after
the provider of such assistance... ;-)

No need.

Bob Barrows
 
M

Mr Beaton

Thanks, Rob, for excellent help on my question. However; after going in the
direction of replacing my concatenations with ?, and creating parameters to
insert them, an undesired effect occurs...

My accented characters gets scr3wed up... All scandinavian characters gets
replaced.

The form data is posted using XMLHTTP, but I've verified that the accented
characters pass through that allright. Any/all ideas will be welcome...

Lastly, I appreciate your decline to have me name my firstborn after you, as
it is likely to be a girl... ;)

//Leif Beaton
 
B

Bob Barrows [MVP]

Mr said:
Thanks, Rob, for excellent help on my question. However; after going
in the direction of replacing my concatenations with ?,

You can't use a stored procedure ... ?
and creating parameters to insert them,

Do you mean that literally? IE, are you using CreateParameter to create
parameter objects which you append to the command object's Parameters
collection? Or are you following the advice from my post to use a variant
array to pass the arguments?
an undesired effect occurs...

My accented characters gets scr3wed up... All scandinavian characters
gets replaced.

The form data is posted using XMLHTTP, but I've verified that the
accented characters pass through that allright.

How have you verified this?

Have you used SQL Profiler to check the data that is being passed to your
sql server?

I have little experience with international character sets, but my initial
reaction is to advise you to explicitly add parameters to the command
object's Parameters collection rather than using the variant array technique
I advised in the post I cited. This will allow you to control the datatypes
of the parameter objects.

If you show me a simplified version of your sql statement (just enough to
reproduce the problem), I will be able to get a little more specific.

Bob Barrows
 
M

Mr Beaton

Hey Rob,
You can't use a stored procedure ... ?

Well, I might go that way. Looking into it.
Do you mean that literally? IE, are you using CreateParameter to create
parameter objects which you append to the command object's Parameters
collection? Or are you following the advice from my post to use a variant
array to pass the arguments?

Code:

<%@Language="VBScript" CODEPAGE="1252" LCID="1030"%>
<% response.Charset = "utf-8" %>

<!---- ...and the quick brown fox and so on... ---->

<%
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.ConnectionString = "Provider=SQLOLEDB;Data Source=Cypher;
Database=sqlDebug; UID=user; PWD=pass;"
oConn.Open oConn.ConnectionString

For Each Field In Request.Form
Dim cmdText
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"

Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")

With oCmd
.CommandText = cmdText
.CommandType = 1
.Parameters.Append .CreateParameter("@1", 200, 1, 200, Field)
.Parameters.Append .CreateParameter("@2", 200, 1, 200,
Request.Form(Field))
Set .ActiveConnection = oConn
End With

oCmd.Execute
Next 'Field

Response.Write Request.Form
%>
How have you verified this?

Response.Writing the form data succeeds as expected.
Have you used SQL Profiler to check the data that is being passed to your
sql server?

Can't say I have...
I have little experience with international character sets, but my initial
reaction is to advise you to explicitly add parameters to the command
object's Parameters collection rather than using the variant array
technique
I advised in the post I cited. This will allow you to control the
datatypes
of the parameter objects.

....silly question, but... Isn't that what I have done? *blush*
If you show me a simplified version of your sql statement (just enough to
reproduce the problem), I will be able to get a little more specific.

Code provided above.

The accented characters I expect are limited to twelve, so I _could_ do a
"manual" replace of them, but if there is one thing I have learned over the
years, it's that if it's POSSIBLE to kill the application, a user will
inadvertently do just that... Further more; I want/need/love to learn this,
as I feel it's an essential piece of logic I've lazily skipped.

I really appreciate this. My usual channels of assistance have proven if not
unable, then at least unwillig to assist. My gratitude is yours.

//Leif Beaton
 
B

Bob Barrows [MVP]

I'm rearranging the reply to hopefully make it a little easier to follow (my
fault, I sked the questions in the worng order)

Mr Beaton wrote:
characters gets replaced.
Response.Writing the form data succeeds as expected.

So you receive the result of Response.Write back from the xmlhttp request?
Can't say I have...

It's an invaluable tool that will make it much easier to troubleshoot
problems of this sort in the future. And, it's extremely easy to use. I
remember the first time I used it i did not even need to read the
documentation. You shuld really familiarize yourself with this tool.
...silly question, but... Isn't that what I have done? *blush*

I didn't know until you posted the code ...
Code provided above.

The accented characters I expect are limited to twelve, so I _could_
do a "manual" replace of them, but if there is one thing I have

I don't like doing that as well. The data should be stored as entered. OK,
let's look at the code:
For Each Field In Request.Form
Dim cmdText
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"

Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")

With oCmd
.CommandText = cmdText
.CommandType = 1
.Parameters.Append .CreateParameter("@1", 200, 1, 200, Field)
.Parameters.Append .CreateParameter("@2", 200, 1, 200,
Request.Form(Field))
Set .ActiveConnection = oConn
End With

oCmd.Execute
Next 'Field

This does not help as much as it could have. I have no idea what the
datatypes of fldName and fldValue are ... varchar? nvarchar?

You used 200 for the parameter datatype arguments. According to
http://www.carlprothman.net/Technology/DataTypeMapping/tabid/97/Default.aspx,
this translates to adVarChar which is the proper type to use for SQL Server
varchar columns.

varchar is not an internationally -aware (unicode) datatype. If your column
has a datatype of varchar, then it will not be able to store you Swedish
characters. nvarchar is the datatype to use for unicode data.

So, let's say you knew this and your database columns actually are nvarchar.
In this case, your problem is due to your telling ADO, via the 200 argument,
to convert the string to ASCII, which results in the replacement of
non-ASCII characters. Your solution is to use 202 (adWVarChar) for the
parameter instead of 200. So try this instead:

'this part should be done outside the loop. It only needs to be done once:
Dim cmdText
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"
Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")
With oCmd
.CommandText = cmdText
.CommandType = 1
Set .ActiveConnection = oConn
.Parameters.Append .CreateParameter("@1", 202, 1, 200)
.Parameters.Append .CreateParameter("@2", 202, 1, 200)
End With
For Each Field In Request.Form
With oCmd
.Parameters("@1").Value= Field
.Parameters("@2").Value=Request.Form(Field)
.Execute ,,128
End With
Next 'Field

I am betting that the simpler technique of using a variant array will also
work. Try this code instead:

'this part should be done outside the loop. It only needs to be done once:
Dim cmdText, arParms
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"
Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")
With oCmd
.CommandText = cmdText
.CommandType = 1
Set .ActiveConnection = oConn
End With
For Each Field In Request.Form
arParms = array(Field,Request.Form(Field))
oCmd.Execute ,arParms,128
Next 'Field

In this case both parameters are strings. If you are using datetime or
numeric parameters instead, you should get more explicit. For example, if
passing a datetime value:

On Error Resume Next
dateparm=CDate(Request.Form(Field))
If err<>0 then
Response.Write Request.Form(Field) & _
"could not be converted into a date"
Response.End
End If
On Error GoTo 0
'then, depending on the technique you are using:
arParms = array(Field,dateparm)
' or
..Parameters("@2").Value=dateparm


HTH,
Bob Barrows
 
M

Mr Beaton

Hello Bob,

I've twisted and turned my code, aided by your examples, and here's the
latest
So you receive the result of Response.Write back from the xmlhttp request?

Yup, I did. And now it is blatantly obvious that this is not sufficient. As
I discovered that even though I both can pass the form data to the server
and return the data from the server using XMLHTTP, and have the desired
output even with accented characters, there is some behind-the-scenes magic
going on here. Using your examples, I was able to pass accented chars
through to the DB, as long as either A) the values was passed to the server
by a normal form (not XMLHTTP), or B) the values was passed directly to the
parameters (debug style), not collected from the form data.

Apparently, the remainder of this problem is of no interrest to this
particular group, as it now limits itself to the passing of form-encoded
data through XMLHTTP, so I'll go ahead and bash my head against it for a
while. When and If I find a solution, I'll post it to this thread (just in
the odd event that anybody wants to see it ;) ).
It's an invaluable tool that will make it much easier to troubleshoot
problems of this sort in the future. And, it's extremely easy to use. I
remember the first time I used it i did not even need to read the
documentation. You shuld really familiarize yourself with this tool.

I sure will look into this.. :)

The examples I valued the most;
Dim cmdText
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"
Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")
With oCmd
.CommandText = cmdText
.CommandType = 1
Set .ActiveConnection = oConn
.Parameters.Append .CreateParameter("@1", 202, 1, 200)
.Parameters.Append .CreateParameter("@2", 202, 1, 200)
End With
For Each Field In Request.Form
With oCmd
.Parameters("@1").Value= Field
.Parameters("@2").Value=Request.Form(Field)
.Execute ,,128
End With
Next 'Field

I am betting that the simpler technique of using a variant array will also
work. Try this code instead:

'this part should be done outside the loop. It only needs to be done once:
Dim cmdText, arParms
cmdText = "INSERT INTO tblFoo (fldName, fldValue) VALUES (?, ?)"
Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")
With oCmd
.CommandText = cmdText
.CommandType = 1
Set .ActiveConnection = oConn
End With
For Each Field In Request.Form
arParms = array(Field,Request.Form(Field))
oCmd.Execute ,arParms,128
Next 'Field

In this case both parameters are strings. If you are using datetime or
numeric parameters instead, you should get more explicit. For example, if
passing a datetime value:

On Error Resume Next
dateparm=CDate(Request.Form(Field))
If err<>0 then
Response.Write Request.Form(Field) & _
"could not be converted into a date"
Response.End
End If
On Error GoTo 0
'then, depending on the technique you are using:
arParms = array(Field,dateparm)
' or
.Parameters("@2").Value=dateparm

Of course it helped. Mr. Barrows, the only thing that impresses me more than
your ability to help, is your willingness. Thank you for your help
throughout this challenge of mine, it's been a learning experience.

P.s. Norwegian, not swedish. ;-) d.s.

//Leif Beaton
 
B

Bob Barrows [MVP]

Mr said:
Hello Bob,

I've twisted and turned my code, aided by your examples, and here's
the latest

Yup, I did. And now it is blatantly obvious that this is not
sufficient. As I discovered that even though I both can pass the form
data to the server and return the data from the server using XMLHTTP,
and have the desired output even with accented characters, there is
some behind-the-scenes magic going on here. Using your examples, I
was able to pass accented chars through to the DB, as long as either
A) the values was passed to the server by a normal form (not
XMLHTTP), or B) the values was passed directly to the parameters
(debug style), not collected from the form data.
Apparently, the remainder of this problem is of no interrest to this
particular group, as it now limits itself to the passing of
form-encoded data through XMLHTTP, so I'll go ahead and bash my head
against it for a while. When and If I find a solution, I'll post it
to this thread (just in the odd event that anybody wants to see it ;)
).

This may help:
http://msdn.microsoft.com/library/d...html/ef9d941a-a3ea-4ecb-968e-65444176ab88.asp

Also, see if any of these links help:
http://www.google.com/search?hl=en&...GLC:en&q=encoding+XMLHTTPRequest+&btnG=Search

Bob Barrows
 
M

Mr Beaton

Hello Bob,

now I am completely stumped... I have fiddled back and forth with the code,
and now I have a even stranger issue... Client side I encode each name and
value using encodeURIComponent, and serverside I have written a function to
decode it back. The decoding function looks like this:

*****************************
Function URLDecode(strText)
strDecoded = strText
Set oRegExpr = Server.CreateObject("VBScript.RegExp")
oRegExpr.Pattern = "%[0-9,A-F]{2}"
oRegExpr.Global = True
Set oMatchCollection = oRegExpr.Execute(strText)
For Each oMatch In oMatchCollection
strDecoded = Replace(sDecoded,oMatch.value,Chr(CInt("&H" &
Right(oMatch.Value,2))))
Next
URLDecode = strDecoded
End Function
*****************************

This appears to work like a charm... But still no go in the database... So I
made the following alteration to test it:

*****************************
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.ConnectionString = "Provider=SQLOLEDB;Data Source=Cypher;
Database=sqlTest; UID=user; PWD=pass;"
oConn.Open oConn.ConnectionString

Dim cmdText, arParms
cmdText = "INSERT INTO tblTest (fldName, fldValue) VALUES (?, ?)"

Dim oCmd
Set oCmd = Server.CreateObject("ADODB.Command")

With oCmd
.CommandText = cmdText
.CommandType = 1
Set .ActiveConnection = oConn
.Parameters.Append .CreateParameter("@1", 202, 1, 200)
.Parameters.Append .CreateParameter("@2", 202, 1, 200)
End With

For Each Field In Request.Form
With oCmd
.Parameters("@1").Value = URLDecode(Field)
.Parameters("@2").Value = "Å " & URLDecode(Request.Form(Field))
.Execute ,,128
End With
Next 'Field
*****************************

The thing that puzzles me, is that the leading "Å " appears as expected in
the DB, but the rest does NOT. Response.Writing the decoded string yields
the desired result, but the DB states otherwise...

I am utterly baffled by this. Any help is, as allways, appreciated.


//Leif Beaton
 
B

Bob Barrows [MVP]

Mr said:
Hello Bob,

now I am completely stumped... I have fiddled back and forth with the
code, and now I have a even stranger issue... Client side I encode
each name and value using encodeURIComponent, and serverside I have
written a function to decode it back. The decoding function looks
like this:

URLdecode? are you passing values via the URL?
 
M

Mr Beaton

Hello Bob,
URLdecode? are you passing values via the URL?

No, I guess I could have called the function applejuice, but URLDecode was
what I named it. I guess URIDecode would be more appropriate, but still...
:) The fact still remains, I am on the verge of believing my IIS is trying
to get me committed... Apparently, everything works, but it does not. The
problem HAS to lie in the

.Parameters("@2").Value = "Å " & URLDecode(Request.Form(Field))

but still, the URLDecode(Request.Form(Field) part does contain the correctly
formatted accented chars. Nevertheless, only the leading "Å " is stored
correctly in the DB. I pass the data by means of the following function:

function fnSubmitForm(oForm, target) {
var strForm = "table=" + oForm.table + "&"; //table is a custom attribute
of the FORM tag, holding the name of the SQL table to use
var strURL = oForm.action;

for(x=0; x<oForm.length; x++) {
var oTemp = oForm.elements[x];
var strValue = oForm.elements[x].value;

switch(oTemp.type) {
case "checkbox":
if(oTemp.checked) {
if (typeof encodeURIComponent != 'undefined') {
strForm += encodeURIComponent(oTemp.name) + "=" +
encodeURIComponent(strValue) + "&";
} else {
strForm += oTemp.name + "=" + strValue + "&"; }
}
break;
case "radio":
if(oTemp.checked) {
if (typeof encodeURIComponent != 'undefined') {
strForm += encodeURIComponent(oTemp.name) + "=" +
encodeURIComponent(strValue) + "&";
} else {
strForm += oTemp.name + "=" + strValue + "&"; }
}
break;
case "select":
if(oTemp.selected) {
if (typeof encodeURIComponent != 'undefined') {
strForm += encodeURIComponent(oTemp.name) + "=" +
encodeURIComponent(strValue) + "&";
} else {
strForm += oTemp.name + "=" + strValue + "&"; }
}
break;
default:
if (typeof encodeURIComponent != 'undefined') {
strForm += encodeURIComponent(oTemp.name) + "=" +
encodeURIComponent(strValue) + "&";
} else {
strForm += oTemp.name + "=" + strValue + "&";
}
break;
}
}
alert(strForm);

if(true) {
if (window.XMLHttpRequest) { // code for Mozilla, etc.
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() { xmlhttpChanges(xmlhttp,
target); }
xmlhttp.open("POST", strURL, false);
xmlhttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded; charset=utf-8");
xmlhttp.send(strForm);
}
else if (window.ActiveXObject) { // code for IE
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
if (xmlhttp) {
xmlhttp.onreadystatechange = function() {
xmlhttpChanges(xmlhttp, target); }
xmlhttp.open("POST", strURL, false);
xmlhttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded; charset=utf-8");
xmlhttp.send(strForm);
}
}
}

return false;
}


//Leif Beaton
 
B

Bob Barrows [MVP]

Mr said:
Hello Bob,


No, I guess I could have called the function applejuice, but
URLDecode was what I named it. I guess URIDecode would be more
appropriate, but still... :) The fact still remains, I am on the
verge of believing my IIS is trying to get me committed...
Apparently, everything works, but it does not. The problem HAS to lie
in the
.Parameters("@2").Value = "Å " & URLDecode(Request.Form(Field))

but still, the URLDecode(Request.Form(Field) part does contain the
correctly formatted accented chars. Nevertheless, only the leading "Å
" is stored correctly in the DB. I pass the data by means of the
following function:

I'm still not clear why you are encoding the data.

My preference when using xmlhttp is to send a well-formed xml document
rather than the raw form data. You can see that in action in my dynamic
listbox demo available here:
http://www.thrasherwebdesign.com/index.asp?pi=links&hp=links.asp&c=&a=clear

With an xml document, you can use CDATA sections to avoid the necessity of
encoding your data.

In any case, this issue has definitely gone beyond my experience, and I
think it's time you brought it to the attention of the experts in one of the
xml newsgroups. I do hope that when you get a solution that you will take
the time to come back and share it with us.

Bob Barrows
 
B

Bob Barrows [MVP]

Mr said:
Hello Bob,


No, I guess I could have called the function applejuice, but
URLDecode was what I named it. I guess URIDecode would be more
appropriate, but still... :) The fact still remains, I am on the
verge of believing my IIS is trying to get me committed...
Apparently, everything works, but it does not. The problem HAS to lie
in the
.Parameters("@2").Value = "Å " & URLDecode(Request.Form(Field))

Wait a minute. I wonder if the solution could be as simple as:

..Parameters("@2").Value = "Å " & _
Cstr(URLDecode(Request.Form(Field)))

Bob Barrows
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,260
Messages
2,571,038
Members
48,768
Latest member
first4landlord

Latest Threads

Top