Industry analysts have estimated that over 70% of today's security
breaches occur at the application level. Many are due to the
exploitation of security defects within the code.
Microsoft's renewed commitment to security has focused the
development community on the need to develop secure Web applications.
With this in mind, Microsoft has added a tremendous number of
features to the .NET environment to aid developers in creating secure
applications. For example, authentication has become an integrated
part of the development environment and debug messages are now
disabled by default. With these improvements, developers are now
realizing the need to integrate security into their Web application
development process.
Web applications can take many forms - including an informal
Web site, an online e-commerce application, an extranet, an intranet,
an exchange, a search engine, or a transaction engine. Regardless of
the type of Web application, it is critical that developers remember
that a Web application includes not only the code that creates the
Web site, but also the underlying components necessary to make the
site available and useful to the public. Often these architectural
components create an open door for attack that many developers do not
consider until an attack occurs. By then, of course, it is too late.
Attacks Focused on the Application Level
As we've seen in the news, all Web sites run the risk of
being hacked, from large consumer e-commerce sites and portals such
as Yahoo! to government agencies such as NASA and the CIA. In the
past, the majority of security breaches occurred at the network layer
of corporate systems. However, today's attackers are manipulating Web
applications inside the corporate firewall, enabling them to access
and sabotage any and all information. Given even a small hole in a
company's Web application code, an experienced attacker armed with
only a Web browser can break into most Web applications.
Prevention of security attacks should start in the
development stage of Web applications. .NET developers and
programmers must realize that not only is it their responsibility to
build workable, usable code, but also to develop attack-proof, secure
code.
In this article developers will learn common coding security
mistakes and how to resolve them - ensuring the proper levels of
security in their Web applications. Here are the top three security
mistakes that developers make during Web application creation in the
.NET environment.
Mistake 1: SQL Injection
SQL injection is the act of accidentally passing SQL code
into an application. These potential attack strings are composed of
fragments of SQL syntax that can be executed on the database server
if the Web application uses the string when forming a SQL statement
without first parsing out certain characters.
For example, problems can arise when a developer does not
protect against potentially malicious input such as a " ' ", which
could close the SQL string and give the user unintended system and
application access.
An example of SQL injection would be for the user to enter
the following string for the e-mail address and password:
' OR '1' = '1
The SQL statement passed to the database now reads like this:
SELECT CustomerID FROM Customers WHERE EmailAddress = '' OR '1' = '1'
AND Password = '' OR '1' = '1'
Since the WHERE clause of the SQL statement will be satisfied by the
always-true condition '1' = '1', the SQL statement will return the
complete list of CustomerIDs in the database and the login will
succeed. Here is another example of a more destructive SQL injection:
Email: '; DELETE FROM Customers; --
Password: x
The SQL now reads:
SELECT CustomerID FROM Customers WHERE EmailAddress = ''; DELETE FROM
Customers; -- ' AND Password = 'x'
The double-dash (--) sequence marks the beginning of a comment, and
any text after that is ignored. So, this statement first executes a
SELECT statement (which returns no rows) and then proceeds to delete
every row in the Customers table.
The following example function is a login that is vulnerable
to SQL injection. By passing the login name and password directly into a SQL query, the
attacker now has the ability to easily modify the SQL query itself.
The result: the attacker can bypass the login and possibly execute
commands on the system and grab all the other users' data.
In order to eliminate this vulnerability, developers need to
pass the name and password to the database in such a way that special
characters aren't interpreted as part of the SQL command. The best
way to do this is to avoid constructing ad hoc SQL statements, and
instead pass the e-mail address and password as parameters to a
stored procedure. This will have the added benefit of improved
performance.
If a stored procedure cannot be created on the database
server, then a good second option is to declare the SQL statement as
a parameterized query. For example:
SELECT CustomerID FROM Customers WHERE EmailAddress = @EmailAddress
AND Password = @Password
The application will not have the performance benefit that comes from
stored procedures, but it will be protected from SQL injection
attacks. Listing 1 is an example of SQL injection. SQL code is
accidentally passed into the application. Listing 2 shows how to use
stored procedures to avoid building the SQL Query. The code sample is
from the IBuySpy Store Sample (www.asp.net/ibuyspy/downloads.aspx?tabindex=5).
Mistake 2: Cross-Site Scripting
Taking user input and returning it to the user without proper
encoding causes cross-site scripting. Cross-site scripting (also
known as XSS or CSS) occurs when dynamically generated Web pages
display input that is not properly validated. This allows an attacker
to embed malicious JavaScript code into the generated page and
execute the script on the machine of any user who views that site.
To demonstrate cross-site scripting, enter the following text
into any form field whose value will be displayed on the page after
it is posted back (for instance, the search field on a search engine):
<script>alert('Vulnerable')</script>
If, when the page posts back, you see a pop-up message box
with the message "Vulnerable", then that page is vulnerable to
cross-site scripting.
An attacker who uses cross-site scripting might successfully
compromise confidential information, manipulate or steal cookies,
create requests that can be mistaken for those of a valid user, or
execute malicious code on end-user systems.
Cross-site scripting occurs on many search engine Web sites.
It is simply a glaring hole that allows an attacker to embed HTML and
JavaScript tags into his search in order to get the browser to
execute it. Solving cross-site scripting attacks in .NET is simple.
By passing all user input through the Server.HTMLEncode() function,
the cross-site scripting hole is automatically fixed. Listing 3 is an
example of cross-site scripting source code for a vulnerable Web
site. Listing 4 shows how to prevent cross-site scripting by passing
all user input through the Server.HTMLEncode() function.
Mistake 3: Enabling Debug Options in the Web.Config File
The <CustomErrors> section of the Web.Config file tells a
.NET application how to deal with errors. An application should never
show an end user a detailed error message. Instead, it should show a
"friendly" message that says the site is having technical
difficulties, and not give any technical details.
Attackers gain a tremendous amount of information from error
messages. Enabling detailed error messages in an ASP.NET application is a major security concern. Table 1 shows the possible settings for <CustomErrors>. Always check
your <CustomErrors> and ensure that the right level of information -
remember, no detail - is returned to the user.
Avoiding the Top Three Mistakes
In an ever-changing, dynamic environment like the Web it is
essential to maintain a security mindset and tools that are always
up-to-date. After all, attackers are constantly updating their
approaches and techniques, so developers must do the same. Security
must be built into the Web application development process itself -
not just reviewed after the application is available to the public.
With a clear understanding of the risks and threats involved
in Web application development, SPI Dynamics has created a powerful
security tool for developers - WebInspect.
WebInspect is a stand-alone software package that can analyze
any Web application, identify potential security flaws, and supply
the developer with the latest information necessary to resolve
security issues before attackers are able to penetrate the system.
To avoid the most common .NET security mistakes, remember:
1. Never accidentally expose code.
2. Keep current on all aspects of security to stay ahead of the attacker.
3. Rely on tools that can help you spot potential security
breaches and resolve the issues.
About The Author
Caleb Sima, founder and CTO of SPI Dynamics (www.spidynamics. com), is widely known in the Internet security community for his expertise in penetration testing and his ability to identify emerging security threats. He began his security career at the S1 Corporation, before joining Internet Security Systems as a member of the X-Force.
csima@spidynamics.com
Listing 1
Public Function Login(ByVal email As String, ByVal password As String) As String
' Create Instance of Connection and Command
' Object
Dim myConnection As SqlConnection = New
SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
Dim myCommand As SqlCommand = New SqlCommand
("SELECT CustomerID FROM Customers
WHERE EmailAddress = '" & email & "'
AND Password = '" & password & "'", myConnection)
myCommand.CommandType = CommandType.Text
' Open the connection and execute the Command
myConnection.Open()
Dim myReader As SqlDataReader = myCommand.ExecuteReader()
Dim customerId As Integer = 0
While myReader.Read()
customerId = CInt(myReader.GetValue(0))
End While
myConnection.Close()
Return customerId.ToString()
End Function
Listing 2
Public Function Login
(ByVal email As String, ByVal password As String) As String
' Create Instance of Connection and Command
' Object
Dim myConnection As SqlConnection = New
SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
Dim myCommand As SqlCommand = New SqlCommand("CustomerLogin", myConnection)
' Mark the Command as a SPROC
myCommand.CommandType = CommandType.StoredProcedure
' Add Parameters to SPROC
Dim parameterEmail As SqlParameter = New SqlParameter
("@Email", SqlDbType.NVarChar, 50)
parameterEmail.Value = email
myCommand.Parameters.Add(parameterEmail)
Dim parameterPassword As SqlParameter =
New SqlParameter("@Password", SqlDbType.NVarChar, 50)
parameterPassword.Value = password
myCommand.Parameters.Add(parameterPassword)
Dim parameterCustomerID As SqlParameter =
New SqlParameter("@CustomerID", SqlDbType.Int, 4)
parameterCustomerID.Direction = ParameterDirection.Output
myCommand.Parameters.Add(parameterCustomerID)
' Open the connection and execute the Command
' myConnection.Open()
myCommand.ExecuteNonQuery()
myConnection.Close()
Dim customerId As Integer = CInt(parameterCustomerID.Value)
If customerId = 0 Then
Return Nothing
Else
Return customerId.ToString()
End If
End Function
Listing 3
' Display a message if no results are found
If MySearchList.Items.Count = 0 Then
ErrorMsg.Text = "Your search for " & Request.Params("txtSearch")
& " returned no results."
End If
Listing 4
' Display a message if no results are found
If MySearchList.Items.Count = 0 Then
ErrorMsg.Text = "Your search for " & Server.HTMLEncode
(Request.Params("txtSearch")) & " returned no results."
End If
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com