asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Protecting Your Web Application Against Dangerous Requests
By Enrico Di Cesare
Rating: 3.5 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    While programming a Web Application, it is very common to split operations between pages. We usually are faced with a page that offers various options (a menu) and a page that processes the request, issues a query against a database, and then shows the results.

    In this case, one of the most common ways to pass parameters from an ASP page to another is via the QueryString. This method is very easy to implement, and sometimes it is the only viable method to accomplish certain tasks. Unfortunately, the method comes with some risks. What if someone writes a request directly in the address bar? Could he/she be able to discover some secret information? This article will show how this could be possible and how to avoid malicious requests.

    Part I - An Easy Example

    First of all, let's imagine a very easy application: a menu with some options and a response page that acts consequently by interpreting the request, querying a db, and then showing the result.

    Menu.asp

    The menu will show 3 common choices: Customer Data, Orders and Invoices.

    
    <%
      Response.Write "List" & "<br>"
      Response.Write "<a href='Response.asp?list=1&custcode=123'>My Data</a><br>"
      Response.Write "<a href='Response.asp?list=2&custcode=123'>My Orders</a><br>"
      Response.Write "<a href='Response.asp?list=3&custcode=123'>My Invoices</a><br>"
    %>
    
    
    For simplicity, all choices point to the same Response.asp page, where the result of the query will be displayed. Also note that the customer code (custcode=123 in this case) is indicated in clear text. Although this isn't a good practice, I'll deliberately leave it clear to explain the article.

    Response.Asp

    The response page will interrogate the database and show the result.

    
    <%
    
    	' declare, instantiate and open connection (Conn)
       ' declare and instantiate recordset (Rs)
    
    	SELECT CASE Request.QueryString("list")
          CASE 1
             strSQL = "SELECT * FROM tableCustomers WHERE custcode=" & _
                      Request.QueryString("custcode")
          CASE 2
             strSQL = "SELECT * FROM tableOrders WHERE custcode=" & _
                      Request.QueryString("custcode")
          CASE 3
             strSQL = "SELECT * FROM tableInvoices WHERE custcode=" & _
                      Request.QueryString("custcode")
       END SELECT
    
       Rs.Open strSQL, Conn
    
       Do While Not Rs.Eof
          ' Show Records
          Rs.MoveNext
       Loop
    
       ' Close Rs & Conn 
     %>
    
    
    This method has a major disadvantage. The user can change the arguments passed by entering different values in the address bar.

    For example, he/she could write an URL like this:

    http://www.mysite.com/Response.asp?list=4&custcode=789

    In the above example, the user changed both the Type and CustCode parameter. In the first case, the Response.Asp page will return an error - an annoying issue, but not so dangerous. In the second case -- which is the worst one -- the user could read values he must not have access to. Furthermore, the Response.asp page is stored in the browser's History, so anyone can read and reproduce it.

    How can we avoid this? The idea is to pass through a middle page that does some conversions. The middle page will convert QueryString parameters into Session values. Of course, we will have to make some changes to the code above. After the modification, the code will be:

    Menu.Asp

    The menu will be modified as follows:

    
    <%
      Response.Write "List" & "<br>"
      Response.Write "<a href='Prepare.asp?list=1&custcode=123'>My Data</a><br>"
      Response.Write "<a href='Prepare.asp?list=2&custcode=123'>My Orders</a><br>"
      Response.Write "<a href='Prepare.asp?list=3&custcode=123'>My Invoices</a><br>"
    %>
    
    
    As you can see, the changes (in bold) were made with a very little effort, so we do not have to redesign the whole application.

    Prepare.asp

    This is the middle page that gets the values in the previous page's form, transforms them into Session values (hidden to the user view), and then redirects the process to the query page.

    
    Session("list")=Request.QueryString("list") 
    Session("custcode")=Request.QueryString("custcode") 
    Response.Redirect "Response.asp"
    
    

    Response.asp

    The response page will be modified as follows:

    
    <%
    
    	' declare, instantiate and open connection (Conn)
       ' declare and instantiate recordset (Rs)
    
    	SELECT CASE Session("list")
          CASE 1
             strSQL = "SELECT * FROM tableCustomers WHERE custcode=" & _
                      Session("custcode")
          CASE 2
             strSQL = "SELECT * FROM tableOrders WHERE custcode=" & _
                      Session("custcode")
          CASE 3
             strSQL = "SELECT * FROM tableInvoices WHERE custcode=" & _
                      Session("custcode")
    	   CASE ELSE
             Response.Redirect("Menu.asp")
       END SELECT
    
       Rs.Open strSQL, Conn
    
       Do While Not Rs.Eof
          ' Show Records
          Rs.MoveNext
       Loop
    
       ' Close Rs & Conn 
     %>
    
    
    Also in this case, the changes (in bold) were made with very little effort.

    This method presents many advantages:

    • The address bar will only report the page name -- a cleaner way
    • The user cannot modify the parameters passed to Response.asp, since it doesn't read the QueryString parameters. It only reads some Session values that are not able to be set by the user
    • The browser's History doesn't store the parameterized Prepare.asp page, so it is difficult to reproduce it.

    I said "difficult", not impossible. Why? First of all, anyone can read it in the browser's status bar (unless you use some Javascript to hide it). Furthermore, a skilled user can still read the HTML source of Menu.asp and locate the lines where the page recalls the Prepare.asp page, and then reproduce the call. Even in this case, there is a solution, which will be explained in the second part.

    Part II - Block Them Outside

    In the first part of this article we discovered how to hide the Querystring from the address bar, and thus introducing some sort of protection against its unauthorized use. But, at the same time, we admitted that a skilled user would have no difficulties breaking this protection. Even worse, an ASP programmer could write a script that calls the page with several parameter combinations to grab the contents of your database.

    So, we must find a way to avoid this.

    The basic idea is to block those requests that come from outside our Web site. Does a server variable exist that reports the origin of a reqeust? Yes, it is HTTP_REFERER, which uses the following syntax: Request.ServerVariables("HTTP_REFERER"). Let's see the description of this variable (from Microsoft's site):
    HTTP_REFERER: Returns a string that contains the URL of the page that referred the request to the current page using an HTML <A> tag.

    Ok. This is the variable that we need. Please note another (very useful) behavior: when you request the page by typing the URL in the address bar, HTTP_REFERER is empty, even if you typed the whole exact URL!

    At this point it is easy to implement a further protection scheme, which is to compare the requester's address with our Web site's address:

    
    IF INSTR(Request("HTTP_REFERER"), "http://www.mysite.com/") <> 1 Then
       Response.Redirect "Menu.asp"
    End If
    IF INSTR(Request("HTTP_REFERER"), "http://10.10.10.212/") <> 1 Then
       Response.Redirect "Menu.asp"
    End If
    
    
    Which pages do we need to protect (in our example)? At the least, the Prepare.asp page should be protected, since it is the page that reads the QueryString. We do not need to protect Request.asp, since that page relies upon the contents of the Session variables, not the QueryString. Also, remember that an external requester cannot pass Session variables to our application.

    Prepare.asp

    Here's how to modify the page (changes are in bold).

    
    
    IF INSTR(Request("HTTP_REFERER"), "http://www.mysite.com/") < 1 Then
       Response.Redirect "Menu.asp"
    End If
    IF INSTR(Request("HTTP_REFERER"), "http://10.10.10.212/") < 1 Then
       Response.Redirect "Menu.asp"
    End If
    
    Session("list")=Request.QueryString("list") 
    Session("custcode")=Request.QueryString("custcode") 
    Response.Redirect "Response.asp"	
    
    
    In our small example, this could be enough to block unauthorized requests. But Web applications usually are far more complex. We should think to implement some function, as part of an include file, to report in each page.

    The function will be:

    
    Function FromSite()
       IF INSTR(Request("HTTP_REFERER"), "http://www.mysite.com/") = 1 Then FromSite = True: Exit Function
       IF INSTR(Request("HTTP_REFERER"), "http://10.10.10.212/") = 1 Then FromSite = True: Exit Function
       FromSite = False
    End Function
    
    
    Then we can call and use the function this way:
    
    If Not FromSite Then 
       Response.Redirect "Menu.asp"
    End If
    
    
    You can easily add programming gadgets, including but not limited to: alert messages, access log, alert mail to the admin, and so on.

    Conclusion

    A Web application may be comfortable to build and implement thanks to smooth technologies such as ASP. But do not forget that they are public; they're "by nature" exposed to attacks. In this article we've learned how to block requests that aren't originated by the Web site by issuing a virtual firewall against external, not authorized, and potentially dangerous requests.

    Check out a demo

    About the Author

    Enrico Di Cesare has more than 20 years of programming experience. After a short experience in COBOL, he worked with all flavors of Basic. Starting withVB3, he began to develop Windows-based applications. Then he embraced ASP from its earlier version, developing business Internet/Intranet solutions. He currently owns a firm based in Italy, which specializes in consulting and design and development of desktop/client-server/internet applications using VB and ASP. You can reach him by email at mailto:edicesare@dicesare.com

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    AspEncrypt
    Built around the Microsoft CryptoAPI, AspEncrypt helps you harness all major encryption and hashing algorithms such as DES, Triple-DES, RC2, RC4, RSA, MD5 and SHA1 in just a few lines of code. The component can be used in tandem with AspEmail to send encrypted and signed mail in the industry-standard S/MIME format, or with AspUpload to encrypt files as they are being uploaded. AspEncrypt can also be used to issue and manage X.509 digital certificates.
    [Top]
    AspPDF
    AspPDF is an ASP/ASP.NET component which enables generation and management of documents in PDF format. Features include advanced text formatting, font embedding, form fill-in, images, tables, content and page extraction, document stitching, encryption, digital signatures, and more.
    [Top]
    Other Articles
    Aug 7, 2002 - Using MySQL in the Win32 Environment
    Developers who don't want to spend a lot of money on SQL Server and who want a database that's more robust than Access may find MySQL to be a pleasant alternative. This introductory article covers the bare essentials for getting MySQL installed and running in the Win32 environment.
    [Read This Article]  [Top]
    Jul 17, 2002 - Software Development: Steps To Better Ensure Success
    There is never a guarantee of project success when endeavoring to build a sophisticated application. However, there are established steps to follow that will ensure a clear, concise scope, support for the team involved, and a solid opportunity for successful deployment.
    [Read This Article]  [Top]
    Jul 15, 2002 - Securing SQL Server for Web Applications
    If your SQL Server is exposed to the Internet, then hackers are probing it. This article shows how to secure a SQL Server database that's being used with a Web application
    [Read This Article]  [Top]
    Apr 2, 2002 - Object-Oriented Programming for VBScripters
    Feel intimidated by .NET? This article by Rob Chartier is designed to ease any level VBScripter (ASP) into .NET by clarifying some OOP concepts.
    [Read This Article]  [Top]
    Mar 27, 2002 - A Best Practice for Using ADO Objects
    A few members of the 15 Seconds discussion list talk about the proper way to use methods in order to prevent ADO object errors.
    [Read This Article]  [Top]
    Jan 2, 2002 - The ASP.NET Page Life Cycle
    Solomon Shaffer explores the life cycle of an ASP.NET page from initialization to unloading. He also explains the various methods to override ASP.NET server-side events.
    [Read This Article]  [Top]
    Dec 19, 2001 - Application Architecture: An N-Tier Approach - Part 2
    Rob Chartier creates a simple portable and reusable address book in .NET to demonstrate the power of N-tier application architecture. Complete source code included!
    [Read This Article]  [Top]
    Oct 23, 2001 - Application Architecture: An N-Tier Approach - Part 1
    Learn about N-tier application architecture and realize that developing with multiple layers produces a flexible and reusable application for distribution to any number of client interfaces.
    [Read This Article]  [Top]
    Oct 23, 2001 - Application Architecture: An N-Tier Approach - Part 1
    Learn about N-tier application architecture and realize that developing with multiple layers produces a flexible and reusable application for distribution to any number of client interfaces.
    [Read This Article]  [Top]
    Sep 11, 2001 - Randomizing a Recordset
    Ed Myers' article shows several ways to use a SQL calculated field and the ORDER BY clause to arrange a recordset in random order. A simple tool is provided for verifying that the results are uniformly random. A technique for bubbling records with certain attributes to the top of an otherwise randomized list is also shown.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers