The security quality of an application is greatly enhanced if the development team creates a threat model and performs a security code review. As part of the effort, it is imperative to ensure that architects, developers and testers pay careful attention to configuration management issues during the design and development of an application rather than leave it to administrators at deployment.
In earlier articles, we have discussed how threat modeling helps us model the system as an attacker would see it, while still leveraging intimate knowledge of the design and architecture. This enables us to make intelligent and perhaps more important, conscious risk management decisions. Security code inspections take that one step further by attempting to look for design and architectural flaws as well as language-specific implementation bugs.
The recent article on security code inspections mentioned eight vulnerability categories. (Software Magazine, Summer Edition 2005, p. 14, or online.) In a series of articles to follow, we will go further in-depth into each of those categories, seeking examples of both bad and good practices, and offering specific recommendations of what to look for as a developer, and how to prevent problems as an architect or developer.
This article will cover the often-ignored but broad and important category of configuration management. We will follow this with articles on cryptography, authentication, authorization, user and session management, data validation, exception management and auditing and logging.
Administrators and deployment experts have traditionally handled configuration management issues, and little or no attention has been paid to this broad category during design and development. Architects and developers often mistakenly assume this task is not important during the initial phases of the development life cycle and decide it is best left for the deployment phase. But early product design and architecture discussions rarely include administrators and security personnel. When security personnel and administrators are not involved early in the life cycle, developers often make assumptions that do not reflect the real-world deployment conditions for the application. Further, when the developers, security personnel and administrators realize the problem, it is often too late to correct the code. As a result, all parties make compromises, which often severely affect the application’s security.
Perhaps the best example of this is the choice of process accounts. Generally speaking, developers write and test code while running as administrators on their local machines. Hence, most operations “just work.” In production environments, however, security policies and standards often demand that the application run as a low-privileged user. Hence, during application deployment all hell breaks lose and a blame game ensues when the application fails to operate correctly due to a lack of permissions.
Application Trumps Security
In our experience, having performed dozens of security reviews, we have seen that business needs to get the application released generally triumph over the security posture. Consequently, the application is deployed and run as a high-privileged user in an insecure configuration. If security personnel, administrators and development teams coordinated early in the life cycle, this issue could be handled before writing a line of code—saving time, money and preventing potential security breaches.
For instance, if these application developers were creating temporary files under the program files directory—for example, /opt/appname or C:\Program Files\appname—simply moving those files to the /tmp directory in Unix or the All Users profile directory on Windows, could eliminate one dependency for super-user privileges. However, this is a choice most developers and architects would rather make early in the application’s life. To prevent such problems from manifesting themselves, an often recommended but rarely implemented best practice is to ensure developers write code at the same privilege level at which the code is expected to run. This forces developers to make informed and well-thought-out decisions with respect to permissions their code requires to run successfully in production.
With that said, what are some of the key configuration management issues that development teams should focus on to improve the security of their code?
Access Control Is Key
Fundamentally, most configuration management issues come down to access control decisions. As the example above indicates, you need to determine early in the software development life cycle (SDLC) what privileges each applications process will run under. This simple “know your deployment security context” pattern affects not only the choice of APIs but can also significantly impact application design. This is due to privilege separation. Privilege separation, or compartmentalization, allows developers to separate those operations and tasks that require elevated privileges and place them in a separate executable. This eliminates the need for running the entire application with super-user privileges.
For instance, within the .NET framework, we strongly recommend that developers run their ASP.NET applications in a partial- or medium-trust environment, in order to protect the underlying host as well as other Web applications hosted on that machine. However, some operations such as reading and writing to certain parts of the file system might need full trust. A recommended approach here leverages privilege separation to place those operations needing full trust into a library then installed into .NET’s global assembly cache. Highly privileged operations must be extremely well reviewed for security flaws to ensure they cannot be compromised.
Configuration management decisions must determine the user/process identity as well as the executing code’s identity. For instance, even though the user running the application has unrestricted access to the local file system, code identity permissions may restrict an application running from the Internet zone to just read access and that to only within a specific directory. In the .NET framework, these decisions can be made fairly intuitively using the configuration tools that ship as part of the framework. However, to make the correct decisions, it is critical that both developers, who make choices regarding API usage, and administrators, who enforce runtime policies, must be on the same page from day one.
Prohibiting Access over the Internet
Controlling access to administrative interfaces is another critical configuration management decision. In most cases, access to administrative services should not be allowed over the Internet and may be locked down even further using technologies such as IPSEC. Multifactor authentication mechanisms such as RSA SecureID are also often used to enhance access control to such interfaces. These stronger authentication mechanisms rely on more than just a user name/password combination to authenticate the user to the application. However, while the administrative interface is perhaps the most powerful piece of an application, in our experience it is tested the least! Even when administrative interfaces are tested, rarely does the development team take into account the deployment scenarios and complex authentication mechanisms described above.
Access to configuration stores such as databases and configuration files (web.config or web.xml, for instance) must be carefully controlled. These stores often contain information such as credit card numbers, passwords and access control information that represent the most critical assets in the system and are therefore often the target of an attack. As recent experience has shown us, the consequences of a leak can have a severely damaging effect not just on the application itself but on the business as a whole. 1
Log Files also Critical
Another instance where configuration management decisions are critical to the application’s security is with log files. Auditing and logging can be tremendously powerful tools for debugging problems, investigating security incidents (forensics), enforcing nonrepudiation and identifying and preventing attacks. However, log-file effectiveness is only as reliable as the access controls applied to those files.
For instance, most attackers will tell you one of the first things they do after they have compromised a system is to figure out if they can subvert the logging mechanisms to clear their traces and avoid possible prosecution. For standard applications- and operating-system-based logging, “log wipers” are a standard part of the hacker tool kit. If an attacker is able to modify or delete logged information, the information in the log files can no longer be trusted and therefore is not useful for nonrepudiation or forensics in the hacked application.
In general, all resources used by an application must have a well-defined and accepted access control policy around them. This is true for not only file-system-based resources such as configuration and log files but also for registry keys, database tables as well as the application executables and plug-ins themselves.
Encrypting Sensitive Information
With regard to the cryptography used for encrypting sensitive information, hashing passwords for storage and using digital signatures for integrity, configuration management again plays a significant role. If SSL is to be used, then it is important that all testing activities take this into account. This includes which cipher suites are used and their key lengths. For secure cryptographic key management, keys should be stored in well-protected locations through the use of appropriate access-control mechanisms.
Consider, for instance, Microsoft Data Protection API (DPAPI), which leverages the underlying Windows password infrastructure to avoid explicit key storage. On the Java side, the Java KeyStore object can be used to store keys securely using PKCS #12.
Hardware and third-party software alternatives are also available. Keystores, the passwords used to access the stores, and other files that store keys must obviously be strongly protected. Keys should never be placed in the source code or even in configuration files; developers must always assume that secrets stored in code or configuration files will be compromised. When cryptographic keys are being exchanged, this also must be done using tried-and-tested mechanisms such as Diffie-Hellman or RSA. Thus transport security is guaranteed for the key exchange. Similarly, a clear strategy must be in place to deal with issues such as key revocation and expiry. Certification revocation lists can be leveraged if a public key infrastructure is in place.
Limiting Unauthorized Information Disclosure
Configuration management decisions can also control and limit unauthorized information disclosure. Most Web servers and application server frameworks allow administrators to display generic error messages irrespective of how the individual applications deal with errors and exceptions. Similarly, administrators can help prevent application-level trace information from being displayed to the end user. With the .NET 2.0 framework, the Web.config can control the health monitoring feature and is therefore another instance of a security-sensitive configuration management issue.
Configuration management issues also appear within the application itself. For instance, in the .NET framework it is important to check whether the Web application’s Web.config is overriding any settings from the machine.config. The allowOverride directive in the machine.config file can prevent precisely this from happening when set to false. This is one of many instances where developers and administrators must work together to ensure that functionality and security are balanced given the risk posture of the organization and the business application at hand.
The development team, with input and help from administrators, more heavily influences a number of configuration management issues. Specifically, with regard to the .NET framework code, access security policies can be used to define what an application, as well as specific users and roles within the application, can or cannot do. Such code access security policies have to be replicated within production environments. Similarly, configuration settings such as validateRequest — which is meant to prevent cross-site scripting attacks in ASP.NET applications — and EnableViewStateMac — used to detect data tampering attacks — must be turned on in the Web or machine configuration files.
Dealing with Third-Party Issues
Finally, it is important to have a clear understanding of how the application will deal with third-party add-ons or plug-ins, patches and updates. These could be to correct security, add functionality or fix other types of bugs. Updates to the underlying platform or operating system must be tested in preproduction environments to ensure they do not affect or break functionality. If such updates have an adverse impact, a clear strategy must exist to safeguard the system while still maintaining business function.
A number of applications had to deal with this precise issue due to the many changes designed to improve security in Microsoft Windows XP Service Pack 2. The only correct solution was to use the extensive Microsoft documentation that preceded the release to prepare for it. Updates to the application itself, if handled through an auto-update mechanism, must ensure that the mechanism is bulletproof and cannot be subverted through techniques such as DNS spoofing. Digital signatures present a potentially effective solution to this problem. Similarly with third-party plug-ins some kind of certification mechanism is strongly recommended to prevent unauthorized malware. In general, the application must have an effective mechanism to validate the integrity of patches as well as add-ons and should be able to prevent malicious code from being injected into the application.
In summary, configuration management issues impact all parts of an application from access control to cryptography and from authentication to auditing and logging. Some of these issues are so fundamental that a change necessitates the complete re-architecture and design of the application. As such, you must deal with such issues early in the SDLC in order to avoid late and costly changes to the code base or highly insecure configuration compromises as an alternative.
Mark Curphey is the founder of the Open Web Application Security Project and is director of North American services for Foundstone, now a McAfee Co. Curphey is the former director of software security for Charles Schwab. He can be reached at Mark.Curphey@Foundstone.com.
Rudolph Araujo is a senior software Security consultant at Foundstone. Rudolph is responsible for creating and delivering the threat modeling and security code review service lines. Rudolph is also responsible for content creation and training delivery. He can be reached at Rudolph.Araujo@Foundstone.com.
Footnote:
1 After 40 million credit and debit card accounts were left vulnerable to hackers, Visa USA, Inc. and American Express Co. in July cut ties with CardSystems Solutions of Atlanta. See story at: www.msnbc.msn.com/id/8629796.