Introduction
Some of the most common and dangerous application security vulnerabilities that exist in ASP.NET Web-based applications come not from the C# or VB.NET code that make up its pages and service methods, but instead from the XML code that makes up its Web.config files. Incorrect configurations can open Web sites to application security holes such as session hijacking, Cross-Site Scripting attacks, and even allow the disclosure of private data to attackers.
An additional problem is that Web.config files were designed to be changed at any time, even after the Web-based applications are in production. A well-intentioned system administrator could inadvertently get around application security measures and open the Web site to attack just by modifying the configuration file. And because .NET configuration files operate in a hierarchical manner, a single change to the global Machine.config file could affect every Web site on the entire network.
Part one of this article listed five of the most serious configuration vulnerabilities that are applicable to any ASP.NET Web-based application. This part will focus on authentication and authorization application security issues, and detail another five vulnerabilities commonly found in ASP.NET Web-based applications using Forms authentication. It will also provide some best practices for application security, including locking down your configuration files to ensure that they are not unintentionally modified by well-meaning (but uninformed) programmers or administrators.
6. Cookieless Authentication Enabled
Just as in the "Cookieless Session State Enabled" vulnerability discussed in part one, enabling cookieless authentication in your Web-based applications can lead to session hijacking and problems with application security.
Vulnerable configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms cookieless="UseUri">
Secure configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms cookieless="UseCookies">
When a session or authentication token appears in the request URL rather than in a secure cookie, an attacker with a network monitoring tool can get around application security, easily take over that session, and effectively impersonate a legitimate user. However, session hijacking has far more serious consequences for application security after a user has been authenticated. For example, online shopping sites generally utilize Web-based applications that allow users to browse without having to provide an ID and password. But when users are ready to make a purchase, or when they want to view their order status, they have to login and be authenticated by the system. After logging in, sites provide access to more sensitive data, such as a user's order history, billing address, and credit card number. Attackers hijacking this user's session before authentication can't usually obtain much useful information. But if the attacker hijacks the session after authentication, all that sensitive information could be compromised.
The best way to prevent session hijacking with Web-based applications is to disable cookieless authentication and force the use of cookies for storing authentication tokens. This application security measure is added by changing the cookieless
attribute of the forms
element to the value UseCookies
.
7. Failure to Require SSL for Authentication Cookies
Web-based applications use the Secure Sockets Layer (SSL) protocol to encrypt data passed between the Web server and the client. Using SSL for application security means that attackers using network sniffers will not be able to interpret the exchanged data. Rather than seeing plaintext requests and responses, they will see only an indecipherable jumble of meaningless characters.
You can require the forms authentication cookie from your Web-based applications to use SSL by setting the requireSSL
attribute of the forms
element to true
.
Vulnerable configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms requireSSL="false">
Secure configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms requireSSL="true">
The previous section discussed the importance of transmitting the authentication token in a cookie, rather than embedding it in the request URL. However, disabling cookieless authentication is just the first step towards securing the authentication token. Unless requests made to the Web server are encrypted, a network sniffer will still be able to read the authentication token from the request cookie. An attacker would still be able to hijack the user's session.
At this point, you might be wondering why it is necessary with application security to disable cookieless authentication, since it is very inconvenient for users who won't accept cookies and seeing as how the request still has to be sent over SSL. The answer is that the request URL is often persisted regardless of whether or not it was sent via SSL. Most major browsers save the complete URL in the browser history cache. If the history cache were to be compromised, the user's login credentials would be as well. Therefore, to truly secure the authentication token, you must require the authentication token to be stored in a cookie, and use SSL to ensure that the cookie be transmitted securely.
By setting the requireSSL
attribute of the forms
element to true
, ASP.NET Web-based applications will use a secure connection when transmitting the authentication cookie to the Web server. Note that IIS requires additional configuration steps to support SSL. You can find instructions to configure SSL for IIS on MSDN ( http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/56bdf977-14f8-4867-9c51-34c346d48b04.mspx?mfr=true).
8. Sliding Expiration Used
All authenticated ASP.NET sessions have a timeout interval to protect application security. The default timeout value is 30 minutes. So, 30 minutes after a user first logs into any of these Web-based applications, he will automatically be logged out and forced to re-authenticate his credentials.
Vulnerable configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms slidingExpiration="true">
Secure configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms slidingExpiration="false">
The slidingExpiration
setting is an application security measure used to reduce risk to Web-based applications in case the authentication token is stolen. When set to false
, the specified timeout interval becomes a fixed period of time from the initial login, rather than a period of inactivity. Attackers using a stolen authentication token have, at maximum, only the specified length of time to impersonate the user before the session times out. Because typical attackers of these Web-based applications have only the token, and don't really know the user's credentials, they can't log back in as the legitimate user, so the stolen authentication token is now useless and the application security threat is mitigated. When sliding expiration is enabled, as long as an attacker makes at least one request to the system every 15 minutes (or half of the timeout interval), the session will remain open indefinitely. This gives attackers more opportunities to steal information and cause other mischief in Web-based applications.
To avoid this application security issue altogether, you can disable sliding expiration by setting the slidingExpiration
attribute of the forms
element to false
.
9. Non-Unique Authentication Cookie Used
Over the last few sections, I hope I have successfully demonstrated the importance of application security and of storing your application's authentication token in a secure cookie value. But a cookie is more than just a value; it is a name-value pair. As strange as it seems, an improperly chosen cookie name can create an application security vulnerability just as dangerous as an improperly chosen storage location.
Vulnerable configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".ASPXAUTH">
Secure configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms name="{abcd1234…}">
The default value for the name of the authentication cookie is .ASPXAUTH. If you have only one Web-based application on your server, then .ASPXAUTH is a perfectly secure choice for the cookie name. In fact, any choice would be secure. But, when your server runs multiple ASP.NET Web-based applications, it becomes critical to assign a unique authentication cookie name to each application. If the names are not unique, then users logging into any of the Web-based applications might inadvertently gain access to all of them. For example, a user logging into the online shopping site to view his order history might find that he is now able to access the administration application on the same site and change the prices of the items in his shopping cart.
The best way to ensure that all Web-based applications on your server have their own set of authorized users is to change the authentication cookie name to a unique value. Globally Unique Identifiers (GUIDs) are excellent choices for application security since they are guaranteed to be unique. Microsoft Visual Studio helpfully includes a tool that will automatically generate a GUID for you. You can find this tool in the Tools menu with the command name "Create GUID". Copy the generated GUID into the name
attribute of the forms
element in the configuration file.
10. Hardcoded Credentials Used
Vulnerable configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms>
<credentials>
...
</credentials>
</forms>
Secure configuration:
<configuration>
<system.web>
<authentication mode="Forms">
<forms>
</forms>
A fundamental difficulty of creating software is that the environment in which the application will be deployed is usually not the same environment in which it is created. In a production environment, the Operating System may be different, the hardware on which the application runs may be more or less powerful, and test databases are replaced with live databases. This is an issue for creating Web-based applications that require authentication because developers and administrators often use test credentials to test the application security. This begs the question: Where do the test credentials come from?
For convenience, to avoid forcing developers from spending time on creating a credential store used solely for test purposes (and which would subsequently be discarded when the application went to production), Microsoft added a section to the Web.config file that you can use to quickly add test users to Web-based applications. For each test user, the developer adds an element to the configuration file with the desired user ID and password, as shown below:
<authentication mode="Forms">
<forms>
<credentials>
<user name="bob" password="bob"/>
<user name="jane" password="Elvis"/>
</credentials>
</forms>
</authentication>
While undeniably convenient for development purposes, this was never intended for use in a production environment. Storing login credentials in plaintext in a configuration file is simply not secure. Anyone with read access to the Web.config file could access the authenticated Web application. It is possible to store the SHA-1 or MD5 hash of the password value, rather than storing the password in plaintext. This is somewhat better, but it is still not a secure solution. Using this method, the user name is still not encrypted. First, providing a known user name to a potential attacker makes it easier to perform a brute force attack against the system. Second, there are many reverse-lookup databases of SHA-1 and MD5 hash values available on the Internet. If the password is simple, such as a word found in a dictionary, then it is almost guaranteed to be found in one of these hash dictionaries.
The most secure way to store login credentials is to not store them in the configuration file. Remove the credentials
element from your Web.config files in production applications.
You're Not Out of the Woods Yet
Now that you've finished reading the top-ten list, and you've checked your configuration settings, your applications are secure forever, right? Not just yet. Web.config files operate in a hierarchical inheritance manner. Every Web.config file inherits values from any Web.config file in a parent directory. That Web.config file in turn inherits values from any Web.config file in its parent directory, and so on. All Web.config files on the system inherit from the global configuration file called Machine.config located in the .NET framework directory. The effect of this is that the runtime behavior of your application can be altered simply by modifying a configuration file in a higher directory.
This can sometimes have unexpected consequences. A system administrator might make a change in a configuration file in response to a problem with a completely separate application, but that change might create a security vulnerability in your application. For example, a user might report that he is not able to access the application without enabling cookies in his browser. The administrator, trying to be helpful, modifies the global configuration file to allow cookieless authentication for all applications.
To keep your application-specific settings from being unexpectedly modified, the solution is to never rely on default setting values. For example, debugging is disabled by default in configuration files. If you're examining the configuration file for your application and you notice that the debug attribute is blank, you might assume that debugging is disabled. But, it may or may not be disabled--the applied value depends on the value in the parent configuration settings on the system. The safest choice is to always explicitly set security-related values in your application's configuration.
Ultimately, securing a Web application requires the efforts and diligence of many different groups, from quality assurance to security operations. However, the developer who codes the application itself has an inherent responsibility to instill security into the application from the beginning of the development process. By making security-conscious decisions from the beginning, developers can create applications that users can trust with their confidential information and that are capable of withstanding attacks launched by hackers. As I've tried to show here, sometimes that process can be as simple as making the right decisions when configuring your application.