Implementing security after the fact has a steep cost
associated with it. Fixing software defects after the application goes into
production might cost up to 15 times more than during development. Lax security
also has some other indirect costs, such as damaging a company’s reputation and
losing customers.
While securing an ASP.NET web application can be complex, it
needs to be done on a continuous basis. The .NET framework and ASP.NET in
particular, offer great features to make it easier to properly secure your web
application.
Authentication
Although ASP.NET supports several authentication methods,
Form authentication is the one mostly used by internet applications.
Unfortunately, this approach is not a particularly secured approach as it sends
user’s credentials to the server in clear text. Depending on requirements, you
might want to consider using SSL throughout the site or at least on the login
page.
Since SSL might be impractical for many commercial web
applications, one unique approach that you can consider is using Silverlight.
Silverlight can be embedded on any sensitive page and provide encryption of any
submitted data.
Web application’s authentication can be further enhanced
with the following:
·
Password Policy
Enforce a password policy including strong passwords,
password expiration, and possibly locking user accounts after a few
unsuccessful login attempts.
·
Guessing Credentials – Brute Force Attacks
In addition to the above, you might want to introduce
a random delay of a few seconds upon unsuccessful user login. This would make
brute force attacks impractical to execute (use Thread.Sleep for this
scenario.)
·
Password Hashing
If you manage your authentication store make sure to
hash all user passwords.
Page Authorization & Data Validation
Small web applications are often built as a series of fairly
isolated web pages. Each page is designed to handle its own security and
functionality, basically acting as a mini application. Although this approach
might work when security & maintenance concerns are few, it very rarely
works for a larger web application.
One approach that is commonly implemented, which can offer a
solid data validation and authorization infrastructure, is the development of a
web framework to be used by all ASP.NET web pages in a consistent manner. This
web framework should be designed to employ common authorization and data
validation security check points upon every user request, allowing the
application to streamline and tighten many security aspects throughout the
application.
Building such a web framework in ASP.NET is surprisingly easy.
Using .NET inheritance, we can design one or more ASP.NET base classes to
inherit from the System.Web.UI.Page object. These base classes would run during
each page lifecycle and would verify each user request before the results are
served to the user.
The following page lifecycle events are commonly used to
perform security checks before the page begins processing the request: Init, InitComplete and PreLoad.
Constructing the ASP.NET Web Framework
Structuring base web pages is easy. Let’s assume that our
ASP.NET web application supports three kinds of users:
Unregistered users – allowed to browse anything publicly
available.
Logged-in users – allowed to browse anything that’s public
plus their own private information.
Administrators - same as a logged-in user plus some extra
admin functionality.
Listing 1: base class to serve unregistered users,
and foundation for other base classes
public abstract class BaseWebPage : System.Web.UI.Page
{
...
}
** This class should verify general
information submitted by users, such as URL parameters, form data to some
extent, cookies and other info that is not tied to any particular user.
Listing 2: User base class to be inherited by all
pages used by logged-in users
public abstract class UserWebPage : BaseWebPage
{
...
}
** This class should ensure that the user
is currently logged-in and has access to the page functionality and to the date
they want to view.
Listing 3: Administrator base class to be inherited
by all pages used by administrators
public abstract class AdminWebPage : UserWebPage
{
...
}
** This class should ensure that in the
current user is indeed an administrator.
Linking ASP.NET Page to Our Web Framework
Utilizing the ASP.NET web framework above requires very
minor adjustments to a web page. Rather than using the default ASP.NET page
base class (System.Web.UI.Page) use the appropriate base class defined earlier.
For instance, if we defined a new ASPX page that is supposed
to serve logged-in users we would define it as follows:
Listing 4: Sample ASPX code-behind page serving a
particular user
public partial class ShowUserSettingsPage : UserWebPage
{
...
}
Performing Page Authorization & Data
Validation
Now that we have built our web framework, all we have left
is to verify user authorization per page and to perform general data validation
for each request.
To perform page authorization, we would define one virtual
method on the BaseWebPage class to authorize the current user. Both the UserWebPage
and the AdminWebPage would override this method and provide their own
implementation. We would call this method on Page_Init from the BaseWebPage before
any page processing is taking place.
This might be implemented as follows:
Listing 5: Page authorization & data validation
on BaseWebPage base class
public abstract class BaseWebPage : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
AuthorizeUser();
ValidateSubmittedData();
}
protected virtual void AuthorizeUser()
{
//no need to do anything for unregistered users
}
...
}
** Class calls a virtual method
AuthorizeUser that inheriting classes can implement to force specific user
access rights, and once the user is authorized, the class verifies all data
submitted to the web page.
Listing 6: Page authorization on UserWebPage for
ASP.NET web pages designated for logged-in users
public abstract class UserWebPage : BaseWebPage
{
protected override void AuthorizeUser()
{
if(!User.IsInRole("User"))
{
//user cannot see the page - redirect to appropriate page
}
}
}
** Class overrides the AuthorizeUser to
make sure current user is logged-in.
More on Data Validation
A centralized web framework can offer many security benefits
to web applications, but it often needs to be complemented with page-specific
security measures to ensure proper data validation.
Web pages should employ data validation based on the following
guidelines:
·
Data validation – web pages should enforce strict data validation
on any piece of data not strictly covered by the web framework. This might
include additional type casting (for instance ensures that a piece of data is
an integer) range and length. Regular expressions and Regex class are a great
a great way to constrain input in ASP.NET.
·
Encoding – any web page displaying data on the browser that
cannot be guaranteed to be safe should be encoded using Server.HtmlEncode to
prevent any malicious cross-site scripting (XSS) attacks.
·
URL write actions– avoid performing database write actions
against URL parameters even if data is valid and the user has authorization to
perform such actions. Also ensure that every POST action is actually done from
an internal application page to prevent cross-site request forgeries (CSRF)
attacks.
·
Exceptions – make sure to catch any possible exceptions and only
send user-friendly messages to the browser to avoid revealing any sensitive
information that might reveal an application’s vulnerabilities.
Data Authorization – Data Access Framework
N-tier infrastructure is not a foreign concept to most
ASP.NET developers and can provide substantial benefits in terms of performance
and scalability. Among the many benefits of n-tier architecture, it also can be
used to centralize and enforce strict authorization rules.
To do this effectively, a data access framework should be
built as an isolated component and should be designed to do the following for
each piece of functionality exposed to the ASP.NET web application:
·
Parameter Validation - validate all parameters supplied by the
user for type, range, length, etc.
·
Authentication - ensure that the calling user is a valid user.
·
Authorization – verify that the user has rights to perform the
current database operation.
·
Database Queries - avoid using dynamic SQL queries, if possible,
and only use parameters.
·
User Data - only send back data that the current user is entitled
to view or return user-friendly exceptions.
Application Configuration
Different applications require different configurations but
the focus of this section is on those that fall under the responsibility of the
web developer.
Encrypting Sensitive Configuration Information
Any sensitive configuration information on the web.config
and beyond should be properly encrypted to avoid exposing sensitive details
like connection strings to potential attackers. You can use the web.config protectedData
section to indicate which sections of the web.config file should be encrypted.
The following shows how to protect the connectionStrings
section:
Listing 7: Protecting the connectionStrings section
within the web.config
<protectedData>
<protectedDataSections>
<add name="connectionStrings"
provider="RSAProtectedConfigurationProvider" />
</protectedDataSections>
</protectedData>
** This is a more suitable way to
protect data across different web servers. Unlike DPAPI, the information is not
tied down to any particular machine.
You can now use aspnet_regiis to encrypt the appropriate
section:
aspnet_regiis -pef connectionStrings
"c:\...\MyWebApplication"
Protect Internal Exceptions
Prevent detailed exceptions from being displayed on the
client’s browser entirely or display this only when the client is browsing on
the web server itself.