Developer Product Briefs
Achieve Quality by Securing Web Applications
Quality and testing best practices are necessary for delivery of applications that meet today's protection and integrity needs.
- By Peter Varhol
- 11/01/2006
Achieve Quality by Securing Web Applications
Quality and testing best practices are necessary for delivery of applications that meet today's protection and integrity needs.
by Peter Varhol
November 17, 2006
Despite the recent industry focus on securing corporate networks, cyber intruders are still succeeding in breaking into enterprise applications and compromising data. Their success has cost millions of dollars in lost business and IT resources required to correct the problem and redeploy applications. The protections that have been taken over the last several years are preventing a lot of casual attacks without a specific intent in mind. But the number of successful attacks demonstrates convincingly that these efforts aren't good enough.
Where are current tactics failing to block more attacks? According to Gartner, 75 percent of successful attacks occur through the application, rather than through the network or operating system. This finding indicates that today's security problem does not involve the infrastructure directly; it has to do with the applications that use that infrastructure.
The problem is especially apparent in Web-based applications. Web applications—in particular, those created for use outside of the enterprise—are readily accessible to intruders, and the Web applications' nature and architecture provides for easy access to application code. In addition, developers often use coding practices that, while correct and functional, can unintentionally provide ways for intruders to access the application at a high level of privilege.
One reason for these security vulnerabilities is that developers have an incomplete picture of who is trying to get into their applications. A rogue hacker seeking to intrude primarily as a technical challenge might have been an accurate image during the early days of the Internet, but two other types of hackers have proved more threatening in recent years.
The first is an internal intruder, the disgruntled or dishonest employee, who already has at least some level of access to the network and quite possibly the target application. This type of person might be motivated by thoughts of riches or revenge, and because most enterprises don't adequately protect from an intrusion from inside, this person's attack can be accomplished relatively easily.
The second is a professional intruder, the person who does hacks for a living. Organized crime has discovered the Internet. A skilled person is hired to fake financial transactions or obtain confidential information that can be sold. Terrorists and spies have also become adept at getting information for their own nefarious purposes.
These new types of cyber intruders have prompted enterprise IT organizations to rethink the traditional practice of protecting only the infrastructure. Firewalls, virus checkers, and network traffic analyzers are an important part of securing the enterprise, but today's IT specialists acknowledge that anyone who is able to overcome these defense mechanisms can easily gain further access to systems and data. As a result, organizations are expressing growing interest in building more secure applications.
This interest has several significant implications within the application development life cycle. To properly address security once an application is deployed, you must consider it at each step in the life cycle—the requirements, design, development, and test phases. Security must have visibility similar to application performance and scalability in all decisions made during the application life cycle.
Poor security reflects on the quality of an application. A security hole is a bug that can cause more harm than many other types of common application bugs. But with a combination of good coding practices and testing, you can prevent security bugs, as you would these other types of bugs.
Building security into an application during development presents a technical challenge because no application can be completely secure. You might find thousands of intrusion paths into an otherwise perfectly functional application, including paths that have not yet been discovered. Even a small Web application can have hundreds of different security holes.
Your goal as part of the development team is to ensure that a large proportion of the serious and critical security weaknesses are resolved so that intruders can not find an easy way into an application. If an application is too difficult to hack, the vast majority of intruders will move on to easier targets. Even if attempts to break into a specific application continue, you will find that making intrusion more difficult offers better opportunity for IT professionals to discover and respond.
To best achieve this goal, you need a methodology for building security into the application development life cycle. A methodology provides an organized way of addressing the issue of security during application development and testing. Here are activities that your approach must include to ensure that applications are developed using secure practices:
- Find and fix security vulnerabilities early while writing code.
- Look for security holes during application runtime.
- Test by trying a variety of known intrusions.
These activities summarize best practices for delivering an application with a high degree of security. Coupled with appropriate infrastructure defenses, application security incorporated during development can provide more protection against intrusion and loss of data than firewall approaches.
Identifying Vulnerabilities in Source Code
The best place for you to begin identifying security vulnerabilities during development is when you're writing code. Certain coding techniques produce perfectly functional results, but they offer intruders a way to use the application or the underlying operating system to gain unauthorized access.
For example, most operating systems offer multiple ways to designate the same logical location in the file system. Here is a common way to close one path to a specific location:
FileIOPermissionAttribute(SecurityAction.Deny, Read=@"c:\passwords")
You might call this code a prudent security practice. However, it can leave a back door into your directory and should be avoided when writing applications. If your restricted directory is accessed this way, then you might block access to it by excluding this code. But you can still use the UNC path (\\machine_name\passwords), or another route to the same directory. To address this weakness, you must also identify all possible routes and protect each of them individually.
Some types of coding practices are done for the sake of expedience or convenience, to make the code simpler or to work around a persistent and unresolved error in the application. When these types of practices are used, the application functions properly, but you might be left with insecure code as a side effect. For example, here is code that you might use to disable the ValidateRequest attribute of the Page directive on an ASPX page:
<%@ Page ValidateRequest="false"%>
Setting ValidateRequest to true enables a request for the page to be checked for possible cross-site scripting attacks. You might set it to false if you intend to add your own validations, or if certain data entries were causing the application to crash. However, setting ValidateRequest to false means that intruders can use data entry fields to send commands to the application, database, or operating system, creating a significant weakness.
The types of coding practices demonstrated in these examples appear relatively straightforward. However, you can use hundreds of different practices for dozens of different application scenarios, making it a full-time job to keep track of which practices you're using and how they work. And your coding practices often change based on changes to the language or underlying operating system, and as intruders find new and increasingly inventive ways to defeat insecure coding practices.
Your best opportunity to secure an application early in the development process is by employing secure coding practices. The most effective way to incorporate better coding practices into your development process is through security code reviews, which bring the expertise of the entire team to bear in identifying and correcting security errors.
Security During Runtime
You can detect many insecure coding practices by using best practices when coding, and reinforcing these practices with code reviews. But, you can also identify some insecure coding practices while an application is running under test. This technique can be tricky because it requires some internal knowledge of what the application is doing and how it is doing it.
Permissions are a good example of a security weakness that can be identified during runtime. If an application opens a file for both read and write access, but in practice, it only reads from the file, then the application has received write permissions when these permissions weren't necessary. Why is receiving these permissions a security weakness? Because a file that doesn't normally require write access but can be written to represents a way for an intruder to perform an action that is not normally implemented by the application, an action that can corrupt data or offer privileges on the system.
Observing the behavior of a running application also provides opportunity to discover poor practices, such as passwords that are easy to guess, database connections that are opened but not closed, and unhandled exceptions within the application. These types of poor practices can be used to compromise an application or its data.
A properly-conducted automation of this type of analysis can be both faster and more comprehensive than manual effort. You can automate this analysis by using a product that observes both the internal calls and data transfers within the application, as well as the operating system and software environment in which it operates.
Testing with Known Intrusions
No security testing regime is complete until you try to break into your running application. Even if you have assurance that an application was developed with good coding practices and security in mind, the application still might suffer from inadvertent errors or unforeseen consequences of specific practices. Testing with known intrusions can uncover security weaknesses that are not apparent using other types of analyses.
Although the practice of breaking into your own applications during runtime is not unheard of, you probably don't want to hire a professional hacker to attempt a break-in at this stage of the methodology. As an alternative, you can engage a security consultancy that specializes in mock attacks against applications, but this is typically a one-time event that cannot be performed multiple times across the application life cycle.
A better approach is to automate break-ins with attack simulation, a process by which software creates and pretends to attack an application with known paths of intrusion. Attack simulation is valuable because it verifies that an application cannot be breached by known means. If an application can be breached, then you can fix the application before it goes into production.
Attack simulation can find a wide variety of security weaknesses in an application. One popular and often-successful type of attack is the buffer overflow. Buffer overflow allows an intruder to overwrite the memory reserved for an input value and corrupt an application. Specifically, the intruder can ensure that the original return point of a function is overwritten and insert his own executable code into the new return point.
Another type of attack is entering escape characters, such as "%", into a data field on an application. This trick is known as parameter tampering. If an application is left unprotected from parameter tampering, intruders can exit from an application and send commands to the operating system, database, or run scripts, or change values of cookies. An intruder who is parameter tampering can perform a wide variety of actions that steal or destroy data, or bring down the application or system.
These examples represent relatively simple attacks, but ones that can cause a great deal of damage if successful. You can inhibit or prevent both types of attacks by checking and verifying all user input prior to using it for processing. Any input that doesn't conform to a legitimate entry should raise an exception and be rejected, by sending the appropriate message to the user.
A number of less-known but equally effective attacks can also be performed on a running application. Automatically running these types of attacks at different points in the application development life cycle provides you with the flexibility needed to find potential weaknesses early and ensure that they are addressed during development.
Intrusions develop and change quickly, and you and your development team might find it challenging to keep up with new techniques in intrusions and apply them to your applications. The ability to perform automated attack simulation allows you to more efficiently discover and address new attack techniques, as well as attacks performed at different phases of the application life cycle.
Application Security and the Enterprise
Why is it a problem today to secure enterprise computing assets? You have more to protect than you did in the past. It is true that the assets compromised by security weaknesses today—money, system stability, and data—are the same those compromised ten years ago. But the consequences today are a lot more significant. For example, downtime on an e-commerce Web application can cost an enterprise millions of dollars, and the loss of data might not only be expensive, but it might also be cause for legal or regulatory difficulties.
If you protect only the infrastructure, then anyone who can get past this protection has relatively free reign to create havoc with any application running on the infrastructure. Applications have many known potential vulnerabilities. Once inside an application intruders can easily exploit these vulnerabilities in the pursuit of money, information, or chaos.
Intruders inside the enterprise are already inside the firewall, and frequently have some level of access to applications, making them potentially the most dangerous type of intruders. But other types of intruders, especially professional hackers, have techniques available for getting past infrastructure defenses as well, compromising data, applications, or the entire infrastructures. You can use known techniques for coding and testing in the application development process to ensure that best practices are used for development and that most security weaknesses are found and fixed before applications are put into production use. Automating these practices makes it possible to enable your development team to focus on building features into the application, while also ensuring a high level of security.
Delivering applications that are resistant to intrusion protects the enterprise against theft or destruction of one of its most valuable assets—its information. Just as the enterprise locks its doors and uses alarms for physical security, it increasingly builds secure applications and runs them on protected networks for cyber security. The goal of physical and application security is the same, to ensure that something valuable isn't stolen or destroyed. In additional to building software that enables enterprises to achieve competitive advantages through innovative use of information, you play an equally important role in protecting corporate assets by assuring that intruders can't easily steal or destroy this information.
About the Author
Peter Varhol is editor in chief of FTPOnline. Contact Peter at pvarhol AT fawcette.com.