These days, Web administrators focus most of their attention on securing OSs, routers, and firewalls. But securing your network devices from outside intruders does little good when attackers can use a Web application to drill to the center of your network. Therefore, securing your Web applications is just as important as securing your Web servers and workstations.
By definition, a Web application accepts input from and returns output to the network. Most Web site exploits take advantage of deficiencies in these I/O interfaces. Intentionally or not, Web applications often accept inappropriate input or return inappropriate output, which can leave security holes for intruders to exploit. For example, leaving your Web application's I/O unsecured can expose sensitive information about your system's configuration, your users, and your customers. Intruders who obtain this information can use it to crack your system, impersonate valid users, or steal customer information, which can lead to civil lawsuits or prosecution for violating privacy laws. To avoid such problems, you need to first secure your Web application's output, then secure its input.
Securing the Output
Securing your Web application's output is crucial because intruders can easily exploit unsecured output and cause a lot of damage. To secure the output, you need to remove sensitive data, make session IDs difficult or impossible to discern, secure cookies if you use them, be prepared for good systems to go bad, prevent Cross-Site Scripting attacks, and avoid using Basic authentication.
Remove sensitive data. Web applications often receive and transmit sensitive data, so you need to sufficiently protect that data from unauthorized viewers. To begin, you need to remove from the HTML pages that the application returns to users any sensitive data that isn't explicitly required. For example, an HTML page might include hidden frames to hide data from users. Using hidden frames to hide data works only if the users don't know how to view a page's source code in their browser (e.g., by selecting the Source option on the View menu in Microsoft Internet Explorer—IE). For that reason, using hidden frames is a poor way to secure data. Don't use hidden frames, except maybe to tidy up a window of nonsensitive data.
To determine whether your Web site uses hidden frames, you can perform a text search for the keyword Hidden in the HTML pages' source code. You should search for strings such as TYPE="hidden". If the hidden data is sensitive, you should rewrite the code to remove the data from the page.
Other keywords to search for are Action and Get. The presence of the Action attribute means that the page is going to perform a function, such as sending data from a Web form to the Web server. You use the Method attribute to specify how to send the data. You have two options: GET and POST. Typically, Web administrators use the GET method to send small amounts of data, whereas they use the POST method to send large amounts of data.
To get the data to the server, the GET method embeds the data in a URL, which means that URLs might contain sensitive information. For example, a URL might contain a user's name and password (e.g., http://www.acme.com/bin/query?user=tony&pass=12345). This URL not only appears in the Address text box of the user's browser but also is recorded in multiple places, including the user's Web browser history, Web server logs, proxy logs, firewalls, and even on unrelated Web servers visited through the HTTP-Referer field.
Using the POST method is a safer way to transfer data. This option embeds the data in the body of the HTTP request. The key here is that the data isn't part of the header, which is typically what most systems track and record. Thus, if a search reveals that your HTML code uses the GET method to transfer data, you need to rewrite the code so that it uses the POST method.
Make session IDs difficult or impossible to discern. Session IDs can help you track users' activities on your Web site. You can often see your session ID embedded in the URL of the Web page you're accessing. For example, when I visited an e-commerce site, the URL was http://generic-ecommercesite.com/php-bin/gig_display.php?sid=400305. (I changed the name of this e-commerce site.) This URL shows that my session ID was 400305. When I again logged on to that site a few minutes later, I received a session ID of 400324. By comparing these session IDs, I learned that the site was handing out sequential session IDs. Issuing sequential session IDs isn't a secure practice. If I were to change the URL's session ID to 400323 and press Enter, I would be logged on as the person who accessed the system just before me. Issuing session IDs that fall within a range of values isn't secure either because intruders can usually figure out a valid session ID fairly quickly. Instead, you should make the session IDs exceptionally large numbers and randomly generate them. Even better, you should encrypt the session IDs. For example, my bank's online service encrypts session IDs. Discerning someone else's session ID from a URL such as https://bigbanking.com/cgi-bin/session.cgi?sessargs=UbIJPnF)uz7BRhMQPhiUeZxlDTTGKUOyofbnVupJ2CM= is nearly impossible.
Secure cookies if you use them. When designed improperly, cookies can represent a security threat. An intruder program such as CookieMonster can use a poorly designed cookie to gather information from users' hard disks.
Cookies consist of several fields. One of those fields contains four parameters—Domain, Path, Secure, and Expires—that you can use to secure your cookies. The Domain parameter specifies the domain to which the Web server can send cookies. Some Web administrators simply specify .com as the cookie's Domain parameter, which means that any .com server can request that cookie—a dangerous practice. Instead, you should set the Domain parameter to your domain's name so that other Web sites can't request your cookies. The Path parameter lets you further limit requests for cookies within your Web site. If you set this parameter to a path that leads to your Web site's secured area, the Web server will send cookies to that area only. Setting the Secure parameter to Yes ensures that the Web server transmits cookies only when Secure Sockets Layer (SSL) is in place. That way, the server never transmits cookies in clear text. The Expires parameter specifies when cookies expire. You should set a reasonable expiration date so that the cookie doesn't remain forever on users' hard disks.
Be prepared for good systems to go bad. No matter how good your Web application is, the possibility exists that it might crash someday. Web applications can produce dangerous output when they aren't working. Error messages can provide valuable information to intruders probing your defenses. For example, error messages can reveal the type of application and the application's version number, so intruders know the types of exploits they can deploy. Error messages can reveal a Web application's structure and subroutine names, which might be callable from a Web browser. In the worst case, a Web application might spit back sensitive data, some of which might not belong to the user receiving the error message.
Although you can't predict when your Web application will go awry, most applications support scripted error-handling. You can write a script that displays a simple We are sorry message and provides a nonsensitive error code for the technical support staff. This solution lets you be friendly to users yet unaccommodating to intruders.
Prevent Cross-Site Scripting attacks. You need to protect users from your Web application's output. This statement might sound strange, but intruders can use an exploit called Cross-Site Scripting, in which an email message, a forum discussion, or another medium lures users to an intruder-controlled Web site that has a link to another site, typically a trusted, well-known site (e.g., a major vendor's site, a site with a search engine). When a user clicks the link, the intruder-controlled Web site directs the user to the trusted site but also enters invalid input on the trusted site's input form (e.g., a logon screen, a search page). Embedded in that invalid input is a malicious program that runs as soon as the trusted site returns a message that says something such as Sorry, we can't find X, where X represents the malicious code. Because the user is on a trusted site, he or she will probably let the program run despite a warning message, or the user's browser might be set to automatically accept code from that trusted site.
To prevent intruders from using your Web site for Cross-Site Scripting attacks, you need to filter your Web application's output. IIS 6.0 includes output filtering. Although Microsoft released an output-filtering patch for IIS 5.x and IIS 4.0 last year, new Cross-Site Scripting attacks have come out as recently as April 2002. To protect your IIS 5.x and IIS 4.0 servers from these most recent attacks, you need to download the cumulative patch from Microsoft Security Bulletin MS02-018 (Cumulative Patch for Internet Information Services—http://www.microsoft.com/technet/security/bulletin/ms02-018.asp).
Avoid using Basic authentication. Your authentication process can include sensitive data in its output. Web administrators commonly use the Basic authentication method that's built into the HTTP standard to authenticate Web users. Unfortunately, this method has two serious security shortcomings. First, it includes the user's logon information in the header of every transmission but doesn't encrypt that information. Figure 1 shows a sample HTTP header from a Basic authentication session. Notice the gibberish at the end of the last line. That gibberish is a username and password encoded as a base-64 string. Encoding isn't the same as encrypting, so intruders can easily extract the logon credentials. Second, the Basic authentication method is vulnerable to brute-force attacks. When users receive an Access denied message after three bad logon attempts, they can click Reload or Refresh and get another three tries.
As its name implies, Basic authentication offers only limited protection from unsophisticated attacks. A more secure solution is using SSL with Basic authentication. This solution solves the header problem because SSL encrypts the header data. However, using SSL with Basic authentication doesn't prevent brute-force attacks. Thus, an even better alternative is to use form-based authentication.
As a side note, when a user logon fails, don't provide informative messages such as User doesn't exist or Password invalid. Such messages let the intruders gather valid usernames that they can eventually use in a brute-force attack. A simple message such as Logon failed. Please try again gives a valid user enough information to act without giving away useful information to an intruder.
Securing the Input
Web applications act on users' input. Whether the input is a username and password, a database query, or an order submission, this data, by definition, is coming from an untrusted source. I'm not saying that you shouldn't trust your users, customers, or vendors but rather that you shouldn't trust any data coming from the Web. You have no way of knowing whether that's really Jane Doe from accounting or Joe Hacker from Romania entering that data. You must always assume the worst.
The vast majority of serious security holes in Web applications result from buffer overflows. You could easily avoid this sad situation if the applications were written properly to begin with. However, buggy software isn't going away, so a good plan is to implement a routine that checks the input that users enter in your Web applications. The routine should filter all input fields—even seemingly innocuous fields such as name or address—for size, content, and format.
In UNIX systems, the semicolon (;) and question mark (?) are special characters that tell the OS to take some action. Similarly, in Windows systems, the slash (/) and angle brackets (< >) are special characters. Intruders might include a slash in their input to try to perform a directory traversal and back their way into the directory tree so that they can go where they aren't supposed to be. And if you find angle brackets in users' input, someone is embedding HTML tags.
You have several ways to secure your Web application's input. One option is to permit only regular characters and numbers in the input. Another option is to filter out slashes, angle brackets, and any escape characters specific to your OS. Listing 1, page 4, contains sample code that you can use in a Web application's input forms to filter out special characters. (The code samples are courtesy of Jeff Forristal, "Maintaining Secure Web Applications," http://www.nwc.com/1105/1105ws1.html, and David Rhodes, Auditing Web Applications, SANS Institute, 2001.) If your application requires users to include special characters in their input, you can permit only those characters that the application needs and reject all others.
If you're running IIS, you can take advantage of Microsoft URLScan 2.0. This program filters all input to your Web server, so you can stop dangerous content before it reaches your application. URLScan works on IIS 4.0 and later. You can download the free program from the Microsoft Windows 2000 Web site (http://www.microsoft.com/windows2000/downloads/recommended/urlscan/default.asp).
Besides filtering input, version 2.0 of the program lets you change the server name in the header that the Web server gives to any browser that visits your site. Changing the server name makes the intruders' job that much more difficult: Imagine their reaction when they see you're running HAL9000. To change the server's name, you simply place the new name in the AlternateServerName field in your urlscan.ini file. You can also have the Web server return a blank server name by changing the value of the RemoveServerHeader field from 0 to 1. However, be careful when changing URLScan's default configuration because incorrect settings can damage your Web site. (For more information about the tool, see Randy Franklin Smith, "Protect Your IIS Server with URLScan," page 6.)
Resources Well Spent
Spending time and money to secure your perimeter and host defenses is a good investment. However, you also need to expend resources to make sure your Web applications aren't letting in or leaking out information that could be dangerous to your network, your users, or your customers. Patching up the security holes in your Web application's I/O will lessen the chance of unwanted visitors causing havoc on your Web site.