Monday, December 27, 2010

The Method Used to Send Data to Server In ASP

When the user clicks the submit button (the button used to collect information from the form and send it), it is assumed that the information on the form is sent to the. HTML allows you to specify how this information would be sent. To support this, the <form> tag is equipped with an attribute called method. This attribute can be assigned one of two values:

  • GET
  • POST

GET: If we are using get method for sending data, the information that is being sent would display in the address bar, starting with a question mark. This would be done as:

<form method="get"> .

The information being carried should not exceed 2048 characters (if we consider that each character uses a byte).

Here is an example:

POST: An alternative is to use post method attribute. In this case, the information is sent directly to the server through a protocol (in this case, HTTP) and would not appear in the address bar of the browser.
If you use POST as the method to send data, the information being carried can be as large as the user/visitor's computer memory (RAM) can afford.

<form action="FileName" method="post">

<title>Active Server Pages Tutorials - Lesson 3: Simple Data Input/Output</title>

<h1>Simple Data Input/Output</h1>

<form action="exercise3.asp" method="post">
<table border="0" width="320">
<td width="80">First Name:</td>
<td><input type="text" name="txtFirstName" size="10"></td>
<td width="80">Last Name:</td>
<td><input type="text" name="txtLastName" size="10">
<input type="submit" value="Submit it">


A Request From a Form
As mentioned already, after a user has finished preparing values in a form, he or she can send them to you. To allow you to get values from the user, the IIS library is equipped with an object called Request. When a form is created on a web page, that form becomes a property of the Request object.
The objects that are part of the form constitute a collection and each object of the form becomes a member of this collection. To access an object of this collection, you can pass it to the Request.Form property (this can be referred to as an indexed property because each object can be access using its index). For example, you can pass the name of a control, as a string, as argument. If you use the Request.Form property to access a control, the information should be collected using the POST value of the METHOD attribute of the form. Based on this, to access any control on the form, you would type:


The object you need to access can be passed as the Object argument. For example, you can pass the name of a form's control as Object, but as a string. This can be done as follows:
In future lessons, when we formally learn about arrays and collections, we will review what roles the OptionalIndex factor and the Count value play. For now, we will ignore them.

To calculate the perimeter and area of the square, change the file as follows:

<%@ Language="VBScript" %>


<title>Geometry: The Square</title>


<h1>Geometric Figures: The Square</h1>
<p>A square is a geometric figure made of 4 equal sides joined at their ends to
form 4 right angles.</p>

<form action="square1.asp" method="post">
  <table border="0" width="316">
      <td width="109">Side:</td>
      <td width="52"><input type="text" name="txtSide" size="14"
        value=<%= Request.Form("txtSide") %> >
      <td width="135"><input type="submit" value="Calculate" name="btnCalculate"></td>
      <td width="109">Perimeter:</td>
      <td width="52"><input type="text" name="txtPerimeter" size="14"
        value=<%= Request.Form("txtSide") * 4 %> >
      <td width="135"></td>
      <td width="109">Area:</td>
      <td width="52"><input type="text" name="txtArea" size="14"
        value=<%= Request.Form("txtSide") * Request.Form("txtSide") %> >
      <td width="135"><input type="reset" value="Reset Form" name="btnReset"></td>



Overview of Forms

A form is a particular type of HTML file that allows a visitor to provide values before submitting them to a server. Although most forms on the web are created in HTML, this language doesn't have an inherent mechanism to treat a form. It relies on other languages, mainly called scripts, to process its values. Nevertheless, most forms are created using HTML objects. Therefore, you use a combination of HTML and a script to effectively use a form.

A form is the central control that manages the other controls. Although the controls can send their data to a script, a form can be used to collect the values typed or selected on the controls, gather them as if they constituted one control and make these values available to a validating file (the file is usually located on a (web) server).

Form Creation

To create a form, you use the <form> tag. Because a form is a collection of controls and their values, the form must have an end tag thatlets the browser know where the form closes. This is done with the 
</form> closing tag:


Everything between the <FORM> and the </FORM>
tags belong to
the form and is called the body of the form. Almost anything can go in the
body of the form. You can design it using any HTML tag and make it as
attractive as you wish.
Although the <form> and the </form> tags are enough to create a
form, such a form can hardly communicate with a script. One of the most
important properties you should set for a form is its name. The name
allows a script to refer to the form and it can be used by files on the
server level. To set the name of a form, assign an appropriate string the
attribute of the <form> tag.

Wednesday, December 22, 2010

Trap Error Even After ScriptTimeOut In ASP

In a production environment, it is common to trap any errors that occur in your Active Server Pages (ASP) page by using the statement "On Error Resume Next." However, if a script time-out error occurs, it is not possible to trap that error by using this method because the ScriptTimeout is happening separately from the ASP error collection.

If, however, you make the ASP page transactional, you will be able to, in essence, handle the error. When the script time-out occurs, the transaction will have failed, and if you made any changes to a resource that supports transactions, such as Microsoft SQL Server, the changes will be rolled back. In addition, your ASP page can contain a procedure named OnTransactionAbort() that will execute when the transaction fails, even if the failure was due to a time-out or other error in that ASP page. The client will still receive the ASP 0113, but by using OnTransactionAbort, you have the ability to so something after the ScriptTimeout has occurblack.

Transactional ASP pages must be hosted on Internet Information Server 4.0 or higher. To make an ASP page transactional, the page must contain the "TRANSACTION=requiblack" argument in the @ Directives tag on the first line of the page.

The following code sample demonstrates trapping the script time-out error:

<%@ TRANSACTION="Required" LANGUAGE="VBScript" %>
      <TITLE>Simple Transactional Web Page</TITLE>
     </HEAD><BODY BGCOLOR="White" topmargin="10" leftmargin="10"> 
      <font size="4" face="Arial, Helvetica"> 
      <b>Transactional Web Page</b></font><br> 
      <hr size="1" color="#000000">     <p> 
      This is an example of an Aborted Transaction. 
      This transaction will abort due to a Script  
     Time-out error, which is an error that you     could not trap without a transaction.     </p>   
   <p>     Please wait until the script times out...     </p>  
       Do while 1 = 1  
        'Infinite Loop
        Loop     %>   
   ' The Transacted Script Abort Handler. This sub-routine    
  ' will be called if the script transacted aborts   
      Sub OnTransactionAbort() 
        Response.Write "<p><b>The Transaction just aborted</b>."  
       Response.Write "This message came from the " 
        Response.Write "OnTransactionAbort() event handler." 
      end sub     %>   

ASP @ Directives

We can use @ processing directives in our scripts to send information to IIS about how to process an .asp file.

For example, the following script uses the @LANGUAGE processing directive to set the scripting language to Microsoft Visual Basic ® Scripting Edition (VBScript).

<%@ Language= "VBScript" CODEPAGE=65001%>
<% Dim myvar myvar = "This is my var" Response.Write(myvar) %>
The following five @ processing directives are supported by ASP.
  • @LCID
The Execute method calls an .asp file, and processes it as if it were part of the calling ASP script. The Execute method is similar to a procedure call in many programming languages.

In the following example, the browser language determines which .asp file is executed. (Languages with multibyte characters have not been included in this example because of code page incompatibilities.)
The output from these scripts on a U.S. system is:
Company Name
Welcome to my Website!
The output from these scripts on a German system is:
Company Name
Willkommen zu meinem Website!
--- Welcome.asp ---
Company Name
<% AcceptLang = Request.ServerVariables("HTTP_ACCEPT_LANGUAGE") Lang = Left(AcceptLang, 2) Server.Execute(Lang & "Welcome.asp") %>

--- EnWelcome.asp ---
<% Response.Write "Welcome to my Website!" %>

--- DeWelcome.asp
<% Response.Write "Willkommen zu meinem Website!" %>

Server.Transfer Method

The Transfer method sends all of the information that has been assembled for processing by one .asp file to a second .asp file.

The following example demonstrates transferring from one .asp file to another, as well as sending the session identifier to the client.
The output from these scripts is:

A session ID

I am going to ASP2

The same session ID

--- ASP1 ---
<% Dim sessvar1 Response.Write Session.SessionID Response.Write ("
Response.Write("I am going to ASP2
--- ASP2 ---
<% Response.Write Session.SessionID%>


When you use the Transfer method, the state information for all the built-in objects are included in the transfer. This means that any variables or objects that have been assigned a value in session or application scope are maintained. In addition, all of the current contents for the Request collections are available to the .asp file that is receiving the transfer.

The Transfer method returns the ASP 0173 error, "Invalid Path Character", if the Path parameter contains any of the following characters:

Asterisk (*)

Question mark (?)

Angle brackets (< or >)

Comma (,)

Colon or semi-colon (: or ;)

Single-quote or double-quote (' or ")

Right square bracket (])

Double slashes (// or \\)

If the path you specify in the input parameter is for an .asp file in another application, the .asp file executes as if it were in the application that contains the Server.Transfer command. In other words, all variables and objects that have been given application scope either by other .asp files in the application or by the application's Global.asa file are available to the called .asp file. However, the path parameter must not contain a query string, or ASP returns an error.

Server.Transfer acts as an efficient replacement for the Response.blackirect method. Response.redirect specifies to the browser to request a different page. Because a blackirect forces a new page request, the browser makes two requests to the Web server, so the Web server handles an extra request. IIS 5.0 introduced a new function, Server.Transfer, which transfers execution to a different ASP page on the server. This avoids the extra request, resulting in better overall system performance, as well as a better user experience.

Special ASP File Global.asa

An optional file that can contain declarations of objects, variables, and methods that can be accessed by any ASP page in an application. This file is stored in the root folder of your ASP application and must be named GLOBAL.ASA.An application can only have one Global.asa file.
Global.asa files can contain only the following:

  •  ASP Built-in Object Events 
  •  OBJECT Declarations
  •  TypeLibrary Declarations

The scripts contained in the Global.asa file may be written in any supported scripting language. If multiple event or object scripts use the same scripting language, they can be combined inside a single set of script

When we save changes to the Global.asa file, the server finishes processing all of the current application requests before it recompiles the Global.asa file. During that time, the server refuses additional requests and returns an error message stating that the request cannot be processed while the application is being restarted.

After all of the current user requests have been processed, the server deletes all active sessions, calling theSession_OnEnd event for each session it deletes, closes the application, and calls the Application_OnEnd event. The Global.asa file is then recompiled. Subsequent user requests will start the application and create new sessions, and trigger the Application_OnStart and Session_OnStart events.

Procedures declared in the Global.asa file can be called only from one or more of the scripts associated with theApplication_OnStart, Application_OnEnd, Session_OnStart, and Session_OnEnd events. They are not available to the ASP pages in the ASP-based application.

ASP Built-in Object Events 

• Application_OnStart – This event is called the FIRST time any user hits an ASP page in the same tree as the GLOBAL.ASA. The first hit of any user is considered to be when the application is first invoked. This function is good for loading any default values for application variables, and initializing logs files and such. The application state is reset after the Web Server is restarted, or when the GLOBAL.ASA file is modified. The Session_OnStart will automatically fire when this event finishes.

• Session_OnStart – This event is called the first time each new user hits the ASP application. So, for each session that is created, this event is called. This event is good for setting up any session level defaults or variables that will be needed for the duration of the user session.

• Session_OnEnd – This even will fire when a user ends a session. This can be done by a user logging out manually, or via a specified timeout period (by default 20 minutes). Useful for session cleanup code.

• Application_OnEnd – This final event occurs when the last user ends his or her session. This process normally fires when the web server is being shut down. This is useful for closing files, creating reports, and updating certain usage statistics.

Here is an example of using the GLOBAL.ASA to create a simple hit counter:

<SCRIPT language=vbscript runat="server">

Sub Application_OnStart
End Sub

Sub Session_OnStart
End Sub

Sub Application_OnEnd
End Sub

sub getcounter
  set conn
conn.Open "c:/webdata/counter.mdb"
set rs=conn.execute("select currentcount from datatable”)
end sub

sub writecounter
  set conn=Server.CreateObject("
  conn.Open "
update datatable set currentcount “ &  
end sub

This my web page There have been <%response.write(Application("currCount"))%>
Visitors to this website!

Monday, December 20, 2010

IIS Basic Authentication

On the world wide web, the oldest and most widely supported authentication method is Basic Authentication. IIS Basic Authentication is included as an option when you set up each IIS directory. Any directory you want to protect must be on a NTFS partition.

How to set up IIS Basic Authentication

Setting up IIS Basic Authentication is similar to setting up NTCR.

In Internet Service Manager (IIS1-3) or the Microsoft Management Console for IIS (IIS4 and up) select the directory you want to protect. Turn on Basic (Clear Text) and turn off Windows NT Challenge Response. It is OK to leave Allow Anonymous on.

Create an account for the each user to whom you want to give access, remove the permissions for "IUSR_machinename" from the directory, and add permissions for the users you added.
Alternatively you can set up a group, permit access to that group, and add permitted users to that group.

Remember the user will need execute rights if the directory has any ASP, ISAPI extensions, counters etc.

IIS Basic Authentication is the way to go if you accept the need for SSL and don't mind paying the performance penalty. Keep in mind that you will need a SSL certificate if you don't already have one.

You won't want to use IIS Basic Authentication if you are concerned about the security of your NT accounts and performance. IIS calls LogonUser and ImpersonateLoggedOnUser for each and every request, which is expensive in terms of CPU cycles.

By default when you create a Web site/virtual directory in IIS you will have Anonymous Access AND Windows NT Challenge/Response enabled. Now in order to identify the user accessing your site through their login you can get the username using Request.ServerVariables("LOGON_USER"). This will return a value only if Anonymous Access is DISABLED and you only have Basic Authentication OR Windows NT Challenge/Response ENABLED

In such a case, Request.ServerVariables("LOGON_USER") will give you both the domain name and username in the format: domainName\username. If you just want the username there are a few ways of getting it. For example, you could use:

'displays: DSRC\BEECHWOOD when I login

'To get only the username...
Dim strNTUser, iPos
strNTUser = RTrim(Request.ServerVariables("LOGON_USER"))
iPos = Len(strNTUser) - InStr(1, strNTUser,"\",1)
strNTUser = Right(strNTUser, iPos)

'strNTUser now contains just BEECHWOOD
Or, to make life a little easier just use the split function

Dim arrSomething, strNTUser
arrSomething = split(Request.ServerVariables("LOGON_USER"),"\")
strNTUser = arrSomething(1)

Tuesday, November 30, 2010

Preventing Classic ASP Application from SQL Injection


"An attack technique used to exploit web sites by altering backend SQL statements through manipulating application input."

SQL Injection happens when a developer accepts user input that is directly placed into a SQL Statement and doesn't properly filter out dangerous characters. This can allow an attacker to not only steal data from your database, but also modify and delete it.

SQL (structured query language) is a very powerful gun for hackers. Normally, hackers target the "information collection form" like the registration form, subscription form, login form, etc. Searching this type of form is not a hard task since hackers used a very smart crawler program. In the rest of the article, we will build a ValidateRequest system which can inspect all request variables centrally application-wise as well as page-wise .

We can start describing the problem by giving a common example using Login process. A Common Practice of login form is below.

select * from users where userName='" &  Request.Form("userName") & 
"' and userPass='" & Request.Form("password") & "'

Inline SQL is a very bad practice since it can open the door for hackers. Inline query is used to build dynamic query by taking the user input. So hackers can convert the query to malicious SQL by inputting username as "a or 1=1'--" which will produce a query like below.

select * from users where userName='a or 1=1'-- and userPass =''….

The above will return true always and will welcome (enter) users to the site. This technique is very old and most of us know this technique. Modern hackers are smart enough. Their target was not just to enter into the system rather, but to also make the system worst by injecting bad script into the database and script file. In most of the cases these scripts contain viruses and the affected websites listed as phishing sites in search engines. The latest technique of attack is to execute a stored procedure in input fields like below.


It is quite difficult to understand the commands from the above inputs. But after decoding the HEX code to ASCII string, it can be found.

SELECT, FROM sysobjects a,syscolumns
a.xtype='u' AND 
(b.xtype=99 OR b.xtype=35 OR b.xtype=231 OR b.xtype=167) 
OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C 
 EXEC('UPDATE ['+@T+'] 
 SET ['+@C+']=RTRIM(CONVERT(VARCHAR(4000),['+@C+']))+''
CLOSE Table_Cursor 
DEALLOCATE Table_Cursor;

We have multiple ways to block this type of injection. The recommended process is to use stored procedures with parameterized SQL because they are type safe and length specified. But for the large existing application which never used any parameterized query, it will be a time consuming task to convert every dynamic query to parameterized query. A quicker solution is to build a central monitoring system, which will validate the input variables from all the forms. 

There are multiple ways to collect data in a form. We normally use post variable, query string, and cookie variables to pass information from one page to other pages in ASP. To protect our application from SQL injection attack, we need to validate input by checking the input type, length, format, range, etc. Also, we have to validate that no harmful SQL keyword is used as input data, like drop, declare, cementation ('--'), execute, varchar, char, etc. So first of all, we have to create a black list by which we can detect harmful execution. Validation can be done in both client side and server side. Do not rely on client side validation, since it can be easily bypassed by disabling javascript. So server side validation is a must. Client side validation can be used to improve the user experience and server performance by reducing round trips. We can consider the following functions to validate input string.

Dim BlackList, ErrorPage
BlackList = Array("=","#","$","%","^","&","*","|",";",_
                  "--""/*", "*/""@@",_
                  "nchar", "varchar""nvarchar""iframe"_
'Note: We can include following keyword to make a stronger scan but it will also 
'protect users to input these words even those are valid input
'  "!", "char", "alter", "begin", "cast", "create", 

'Populate the error page you want to redirect to in case the check fails.
ErrorPage = "../displaymessage.asp?msg="
Server.URLEncode("Invalid Character Entered")
Function CheckStringForSQL(str,varType
  On Error Resume Next 
  Dim lstr 
  ' If the string is empty, return false that means pass
  If ( IsEmpty(str) ) Then
    CheckStringForSQL = false
    Exit Function
  ElseIf ( StrComp(str""= 0 ) Then
    CheckStringForSQL = false
    Exit Function
  End If
  lstr = LCase(str)
  ' Check if the string contains any patterns in our black list
  For Each s in BlackList
        If ( InStr (lstr, s) <> 0 ) Then
          CheckStringForSQL = true
          Exit Function
        End If
    End If
  CheckStringForSQL = false
End Function 

The function is very straight-forward. Note that in some cases you might need to allow some character as a valid input to give user flexibility. For example, the user might like to use "$" symbol in password field or our cookie might contain braces "(…)" symbol. So we can make an exception list according to storage variable type and can be checked like the following.

CookieExceptionList = Array("""","(",")")
Function IsExceptionList(str,varType)
        For Each item in CookieExceptionList
                Exit Function
            End If
    End If
End Function

Now we can protect all the form variables using the function "CheckStringForSQL" in the following way.

For Each s in Request.Form
  If ( CheckStringForSQL(Request.Form(s),"form") ) Then
    PrepareReport("Post Varibale")
    ' Redirect to an error page
  End If

The same thing can be repeated for querystring variables and cookie variables. Without these variable types, a lot of asp developers use a third party control ASPUpload to upload files and transfer information from one page to another. That can also validate in the following way.

'  Check Upload forms data
'  Description: This function will validate ASP Upload Data
'  Note:        Because of ASPUpload's limitation this function 
'               need to be called after its save function from 
'               the relevant ASP page
function IsValidUploadFormData(dataCollection,redirect)
    for each item in dataCollection
        If ( CheckStringForSQL(item) ) Then
            PrepareReport("Upload Form")
            'Redirect to an error page
            if(redirect) then Response.Redirect(ErrorPage)
            IsValidUploadFormData = false
            Exit Function
         End If
    IsValidUploadFormData = true
end function

Note: This function needs to be called after calling the Save function of AspUpload manually because before that the data will not be available in the collection.

Additionally, for new projects as well as old projects, we can maintain the following best practices to avoid the attack. 

1. Use escape character routines to handle special characters
2. Use stored procedures rather than dynamic query where possible
3. Use parameterized query incase of dynamic query
4. Use HtmlEncode and decode techniques to show html data where possible
5. Use a least privileged database account- only stored procedure will have the permission for update/insert and script will have only read permission