An attacker may be able to create unexpected control flow paths through the application, potentially bypassing security checks. Exploitation of this weakness can result in a limited form of code injection.
Explanation:
If an attacker can supply values that the application then uses to determine which class to instantiate or which method to invoke, the potential exists for the attacker to create control flow paths through the application that were not intended by the application developers. This attack vector may allow the attacker to bypass authentication or access control checks or otherwise cause the application to behave in an unexpected manner. Even the ability to control the arguments passed to a given method or constructor may give a wily attacker the edge necessary to mount a successful attack.
This situation becomes a doomsday scenario if the attacker may upload files into a location that appears on the application's classpath or add new entries to the application's classpath. Under either of these conditions, the attacker may use reflection to introduce new, presumably malicious, behavior into the application.
Example: A common reason that programmers use the reflection API is to implement their own command dispatcher. The following example shows a command dispatcher that does not use reflection:
String ctl = request.getParameter("ctl");
Worker ao = null;
if (ctl.equals("Add")) {
ao = new AddCommand();
} else if (ctl.equals("Modify")) {
ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
ao.doAction(request);
A programmer might refactor this code to use reflection as follows:
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.doAction(request);
The refactoring initially appears to offer a number of advantages. There are fewer lines of code, the if/else blocks have been entirely eliminated, and it is now possible to add new command types without modifying the command dispatcher.
However, the refactoring allows an attacker to instantiate any object that implements the Worker interface. If the command dispatcher is still responsible for access control, then whenever programmers create a new class that implements the Worker interface, they must remember to modify the dispatcher's access control code. If they fail to modify the access control code, then some Worker classes will not have any access control.
One way to address this access control problem is to make the Worker object responsible for performing the access control check. An example of the re-refactored code is as follows:
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.checkAccessControl(request);
ao.doAction(request);
Although this is an improvement, it encourages a decentralized approach to access control, which makes it easier for programmers to make access control mistakes.
This code also highlights another security problem with using reflection to build a command dispatcher. An attacker may invoke the default constructor for any kind of object. In fact, the attacker is not even constrained to objects that implement the Worker interface; the default constructor for any object in the system can be invoked. If the object does not implement the Worker interface, a ClassCastException will be thrown before the assignment to ao, but if the constructor performs operations that work in the attacker's favor, the damage will have already been done. Although this scenario is relatively benign in simple applications, in larger applications where complexity grows exponentially it is not unreasonable to assume that an attacker could find a constructor to leverage as part of an attack.
Access checks may also be compromised further down the code execution chain, if certain Java APIs that perform tasks using the immediate caller's class loader check, are invoked on untrusted objects returned by reflection calls. These Java APIs bypass the SecurityManager check that ensures all callers in the execution chain have the requisite security permissions. Care should be taken to ensure these APIs are not invoked on the untrusted objects returned by reflection as they can bypass security access checks and leave the system vulnerable to remote attacks. For more information on these Java APIs please refer to Guideline 9 of The Secure Coding Guidelines for the Java Programming Language.
Recommendations:
The best way to prevent unsafe reflection is with a level of indirection: create a list of legitimate names that users are allowed to specify, and only allow users to select from the list. With this approach, input provided by users is never used directly to specify a name that is passed to the reflection API.
Reflection can also be used to create a custom data-driven architecture, whereby a configuration file determines the types and combinations of objects that are used by the application. This style of programming introduces the following security concerns:
- The configuration file that controls the program is an essential part of the program's source code and must be protected and reviewed accordingly.
- Because the configuration file is unique to the application, unique work must be performed to evaluate the security of the design.
-Because the semantics of the application are now governed by a configuration file with a custom format, custom rules are required for obtaining optimal static analysis results.
For these reasons, avoid using this style of design unless your team can devote a large amount of effort to security evaluation.
Tips:
1. Beware of attempts to validate user input before using it as part of a call to a reflection method. Because the application is likely to evolve faster than the operating system, the file system, or other system components, the work required to validate user input must evolve much more rapidly than the input validation required for sending user data to other system components. Even if the validation is currently correct, it might not be correct in the future.
2. A number of modern web frameworks provide mechanisms to perform user input validation (including Struts and Spring MVC). To highlight the unvalidated sources of input, Fortify Secure Coding Rulepacks dynamically re-prioritize the issues Fortify Static Code Analyzer reports by lowering their probability of exploit and providing pointers to the supporting evidence whenever the framework validation mechanism is in use. We refer to this feature as Context-Sensitive Ranking. To further assist the Fortify user with the auditing process, the Fortify Software Security Research group makes available the Data Validation project template that groups the issues into folders based on the validation mechanism applied to their source of input.
0 comments:
Post a Comment