Today’s Web applications are vulnerable to a variety of security attacks that can inflict disaster on an organization. However, thanks to the Enterprise Security API (ESAPI) project, preventing these attacks is possible. In part one of this two-part article, we looked at how “Anonymous” attacks Web applications. Here we will see how these attacks can be prevented.
Preventing directory traversal
Directory traversal is a Web application vulnerability in which the Web application allows malicious users access to files outside of the application’s directories. For instance, an application which runs in \myApp\ and has child directories on a Unix server most likely resides in the \var\www\myApp\ directory on the file system. A secure application would deny access to any directories not in or under \var\www\myApp.
There are two strategies to employ to prevent directory traversal vulnerabilities: preventing directory access with account permission, and writing the application such that it rejects common directory traversal attempts. To control directory access with account permission, it is critical to write Web applications to run in low-privilege accounts. In the development phase, it’s easy to fall into the habit of coding applications with root (Unix) or administrator (Windows) permissions (full access on the entire server). A secure application runs only in the credentials it needs – generally a service account whose access is limited only to the application’s directory structure. While the OWASP Project’s article on Path Traversal has more details, some simple architectural and coding techniques can help prevent these vulnerabilities from being included in your application. These include:
- Programmatically check decoded directory access just prior to execution; if it falls outside of a whitelist of valid directories, deny access.
- Map directories and files to a hash table with indices. Only serve requests which access valid indices.
- Only allow the user to provide portions of a path, rather than the entire path (must be used in conjunction with user input validation, to prevent encoded traversal attempts).
Preventing SQL injection
The most destructive form of attack in terms of numbers of records disclosed is the SQL injection attack (see the Verizon Data Breach Analysis survey). In this attack, hackers attempt to cause a SQL server to interpret user input (which should be data) as code commands. The OWASP SQL Injection Prevention Cheat Sheet enumerates several methods of preventing injection attacks, including:
- Only using parameterized queries: query parameterization guarantees user input will programmatically only ever be used as data. Parameterization will not allow input to be used as an actually command statement.
- Use stored procedures: this is a partial technique which should never be used in place of query parameterized queries, but which works in much the same way. Stored procedures, if written appropriately, can be used to reduce the risk of data being interpreted as commands.
- Validate user input.
As input validation is a deeper topic, let’s explore methods for implementing this strategy. Validating input can be accomplished in a variety of ways:
- Whitelist acceptable input characters: only allow certain characters to be passed from the user into the Web application.
- Blacklist unallowed input characters: prevent certain characters from being passed from the user into the Web application.
- Strong-type input: cast input to Boolean or enum types, discarding non-compliant input. This forces random user input to fall into strict categories or error and is the strongest check for all user input not destined to be stored or used as a string.
- Ensure input falls into acceptable bounds (for instance, a user-provided age should 1) successfully cast to an input and 2) generally be below 150).
One note on whitelisting and blacklisting: Generating whitelists and blacklists often starts a cat-and-mouse game, with hackers leveraging encoding to get around programmatic constraints. As a general rule, if strong typing and input bounds checking aren’t feasible and your only option is whitelisting or blacklisting, it’s recommended that you re-examine your design to see if it can be implemented more security. If you must blacklist or whitelist, it’s a good idea to decode (single or double) user input prior to validation.
Preventing cross-site scripting
Cross-site scripting is the second most common Web application input attack (after SQL injection). The good news is that cross-site scripting (abbreviated as XSS) is generally easy to prevent. The OWASP ESAPI library includes a number of tested APIs which can be called to encode data just prior to displaying it on a webpage. Simply by wrapping data in an encoding call, you can prevent malicious input from being interpreted by the client browser application as executable code.
Implementing the ESAPI encoding library is as easy as this:
Modify the following line:
String username = request.getParemeter(uName);
To look like this:
String username = ESAPI.encodeforHTML(request.getParameter(uName));
In this era of aggressive website hacking, it is a critical responsibility of each organization to develop and deploy secure Web applications. With a little training and an emphasis on a solid secure development lifecycle, it is not difficult to fulfill that responsibility. The examples above demonstrate how a few minor design changes can result in significantly more secure code.
Follow us on Twitter at @SoftwareTestTT and let us know what you thought of this article.