Secure Your Web App
Implementing and following best practices for quality and testing enable you to deliver applications that meet today's protection and integrity needs.
- By Peter Varhol
Technology Toolbox: SQL Server 2005, ASP.NET
Locking down security remains one of the most significant aspects of building any enterprise application.
Yet cyber intruders are still succeeding in breaking into enterprise applications and compromising data, despite an intense focus on securing corporate networks over the last several years. These breeches cost businesses millions of dollars of lost revenues and IT resources as IT corrects for these breeches and redeploys its applications.
Yes, the protections that have been undertaken to date prevent a lot of casual attacks without a specific intent in mind. But the number of successful attacks demonstrates convincingly that current efforts simply aren't good enough.
The problem is especially acute with Web-based applications. Web applications, especially those meant for use outside of the enterprise, are by nature readily accessible to intruders, and their architecture can provide easy access to some 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 privilege level.
Part of the problem is that most of us have an incomplete picture of who is trying to get into our applications. The image of the rogue hacker who seeks to intrude primarily for the technical challenge might have been accurate during the early days of the Internet, but in recent years this type of person has been supplemented by two other groups. The first is the internal person, the disgruntled or dishonest employee, who already has at least some level of access to the network and quite possibly the application. This person might be motivated by thoughts of either riches or revenge, and this kind of attack is often relatively easy to carry out because most enterprises don't adequately protect themselves from internal attacks.
The second type of person is the professional intruder, the person who does it for a living. Organized crime has discovered the Internet, and it uses highly skilled people to fake financial transactions or obtain information that can be sold.
The new face of the cyber intruder means that enterprise IT organizations must 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 IT specialists acknowledge that anyone getting past these defenses typically gain unimpeded access to systems and data. As a result, there is growing interest in building applications that are more secure than they have been in the past.
This has several significant implications to the application development lifecycle. Security can be addressed properly only if you consider it at each step in the lifecycle: requirements, design, development, and testing. Application performance and scalability have been integrated into all decisions made during the application lifecycle, but IT must also integrate security just as deeply.
Make no mistake; poor security reflects on the quality of an application. A security hole is a bug, and one that can cause considerably more harm than other types of bugs often found in applications. Preventing security bugs requires a combination of good coding practices and testing.
Building security into an application during development is a technical challenge, and one major aspect of this challenge is that no application can be completely secure. There might be 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.
One important goal for the development team should be to ensure that a high proportion of the serious and critical security weaknesses are closed, so that intruders have no easy way into the application. The vast majority of intruders move on to easier targets if an application is too difficult to break into. Making intrusion more difficult also gives IT professionals a better opportunity to discover and respond to attacks even if intruders continue to pound at the defenses of a more secure application.
Development teams need an organized way of addressing the issue of security during application development and testing. Several methodologies address the incorporation of security measures during application development, but any approach that seeks to ensure that applications are developed using secure practices should include finding and fixing problems while writing code, looking for security holes during application runtime, and testing by trying a variety of known intrusion techniques.
Coupled with appropriate infrastructure defenses, application security that you build in during the development process can provide far more protection against intrusion and loss of data than simple firewall approaches.
The best place to begin looking for security vulnerabilities during development is when writing code. There are coding techniques that produce perfectly functional results, yet offer intruders a way to use the application or the underlying operating system to gain unauthorized access.
For example, consider the fact that most operating systems offer multiple ways to designate the same logical location in the file system. You might close one path to a specific location like this:
Some might even call this a prudent security practice, except that this can leave a back door into the directory. You might block access to the restricted directory, but only if it's accessed in that specific way. In this case, you can still use the UNC path (\\machine_name\passwords) or another route to that same directory. The way to address this weakness is to identify all possible routes and protect each of them individually.
Developers utilize some types of coding practices for the sake of expediency or convenience, to make the code simpler or to work around a persistent, but unresolved error in the application. In cases like this, the application functions properly, but sometimes a side affect of this approach is insecure code. For example, you might disable the ValidateRequest attribute of the Page directive on an ASPX page in this manner:
<%@ Page ValidateRequest="false"%>
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 try to send commands to the application, database, or operating system; this is a significant application weakness. On the other hand, setting ValidateRequest to true enables you to check a request for that page for many possible cross-site scripting attacks.
These types of coding practices sound relatively straightforward. However, there are hundreds of different practices for dozens of different application scenarios, making it a full-time job just to keep track of what the specific issues are for a given application and how they work. To complicate matters further, security coding issues can change based on changes to the language or underlying operating system. They also change as intruders find new and increasingly inventive ways to defeat insecure coding practices. The best way to incorporate better coding practices is through security code reviews, which brings the expertise of the entire team to bear in identifying and correcting security errors.
Security During Runtime
You can discover and address many insecure coding practices by using best practices during coding and reinforcing those practices with code reviews, but it's also possible to identify some issues while the application runs under test. This can be tricky because it requires some internal knowledge of what the application is doing and how it does it.
Permissions are a good example of a security weakness that you can identify during runtime. If the application opens a file for both read and write access, yet only reads from that file during runtime, then it is receiving write permissions when they aren't necessary. This is a security weakness because the file (that should be read only) can now be written to and that gives a way for an intruder to perform actions that aren't normally performed by the application. An intruder might take advantage of this to corrupt data or even gain privileges on the system.
Observing the behavior of the running application is also a good opportunity to discover poor practices such as passwords that are easy to guess, database connections that are opened but not closed, and even unhandled exceptions within the application. Intruders can exploit any of these security lapses to compromise an application or its data.
Unfortunately, it can be difficult to observe the application's behavior, and then share that behavior with the development team that implemented the application. An IT testing department needs to understand both how the application was developed and under what conditions it will run. A senior developer with a detailed understanding of both the implementation and how the app will be used can accomplish this (with painstaking effort), but you don't always have such developers available. Another approach is to automate this type of analysis 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 the application operates.
Another key aspect of limiting code vulnerabilities is to test against known intrusions. No security testing regime is complete until you try to break into the running application. Inadvertent errors or unforeseen consequences of specific practices can uncover security weaknesses that aren't apparent using other types of analyses even when you have a degree of assurance that the application was developed with good coding practices and security in mind.
In the past, people have hired professional hackers to attempt to compromise their applications during this phase of testing but the practice isn't recommended. You could also engage a security consultancy that specializes in mock attacks against applications, but that is typically a one-time event that cannot be performed multiple times across the application lifecycle.
A better approach is to automate security testing through attack simulation, a process by which software creates and pretends to attack the application with known paths of intrusion. The value of attack simulation is that it verifies that the application cannot be breached by known means. This also gives you the ability to fix and verify potential issues before your application goes into production.
Find Security Weaknesses
Attack simulation can find a wide variety of security weaknesses in an application. One popular and often successful attack is the buffer overflow technique that allows an intruder to overwrite the memory reserved for an input value and corrupt the application. If successful, the intruder can overwrite the function's original return point, substituting a new value pointing to his own executable code.
Another example of an attack is to enter escape characters such as "%" into a data field within an application, a trick known as parameter tampering. Left unprotected, this can enable intruders to exit from the application and be able to send commands to the operating system or database, run scripts, change values of cookies, or perform similar types of actions. In any of these circumstances, the intruder can perform a wide variety of actions that can compromise or destroy data, or even bring down the application or system.
Buffer overflow and parameter tampering are relatively simple attacks, albeit they can cause a great deal of damage if successful. You can inhibit or prevent both of these particular types of attack by checking and verifying all user input prior to processing it. Anything that doesn't conform to a legitimate entry should raise an exception and be rejected; remember to send an appropriate message to the user as you do this (see the sidebar, "Plug Common Security Holes").
There are also many less well-known, but equally effective attacks that intruders can perform on a running application. The ability to have these attacks run automatically at different points in the application development lifecycle gives you the flexibility you need to find potential weaknesses early and ensure that any problems are addressed during development.
Providing security for enterprise computing assets is more important today than is was in the past because there is so much more to protect. It's true that the things you lose from security breeches today—money, system stability, and data—are the same things that you lost 10 years ago, but today the consequences are much more significant. Any downtime at all on an e-commerce Web application can cost an enterprise millions of dollars, and the loss of data can result in more than lost revenue; it can also mean legal or regulatory difficulties for your company.
Protecting your infrastructure from outside attacks is important, but you must protect the applications too. Relying on firewalls alone means that anyone who can get past that level of protection is free to create havoc with any application running within that infrastructure. Applications have many known potential vulnerabilities; once inside, intruders can exploit those 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 the most dangerous kind of intruders your enterprise might face.
But others, especially professional hackers, have techniques for getting past infrastructure defenses and compromising data, applications, or even entire infrastructures. There are known techniques for coding and testing that you can perform during the application development process to ensure that your developers use best practices to reduce most security weaknesses. These techniques can also help you find and fix these weaknesses before you put your applications into production. Automating these practices makes it possible to enable the 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 helps protect the enterprise against theft or destruction of one of its most valuable assets—its information. Just as your enterprise locks its doors at night and uses alarms for physical security, it must build secure applications and run them on protected networks for cyber security.