Show
Secure Coding Guidelines for Java SEDocument version: 9.1
IntroductionJava's architecture and components include security mechanisms that can help to protect against hostile, misbehaving, or unsafe code. However, following secure coding best practices is still necessary to avoid bugs that could weaken security and even inadvertently open the very holes that Java's security features were intended to protect against. These bugs could potentially be used to steal confidential data from the machine and intranet, misuse system resources, prevent useful operation of the machine, assist further attacks, and many other malicious activities. The choice of language system impacts the robustness of any software program. The Java language [2] and virtual machine [3] provide many features to mitigate common programming mistakes. The language is type-safe, and the runtime provides automatic memory management and bounds-checking on arrays. Java programs and libraries check for illegal state at the earliest opportunity. These features also make Java programs highly resistant to the stack-smashing [4] and buffer overflow attacks possible in the C and to a lesser extent C++ programming languages. The explicit static typing of Java makes code easy to understand (and facilitates static analysis), and the dynamic checks ensure unexpected conditions result in predictable behavior. To minimize the likelihood of security vulnerabilities caused by programmer error, Java developers should adhere to recommended coding guidelines. Existing publications, such as Effective Java [6], provide excellent guidelines related to Java software design. Others, such as Software Security: Building Security In [7], outline guiding principles for software security. This document bridges such publications together and includes coverage of additional topics. It provides a more complete set of security-specific coding guidelines targeted at the Java programming language. These guidelines are of interest to all Java developers, whether they create trusted end-user applications, implement the internals of a security component, or develop shared Java class libraries that perform common programming tasks. Any implementation bug can have serious security ramifications and could appear in any layer of the software stack. Some guidelines in later sections focus on situations where a security manager is in place. While most of these guidelines are in section 9, a small number of guidelines in other sections reference the security manager as well. For applications that do not use or need to work with a security manager in place, these guidelines will be less relevant. Also, note that the security manager has been deprecated in Java 173. Additional information and alternatives to the security manager can be found in the introduction to section 9. There are also several guidelines that cover interactions with untrusted code. The concept of untrusted code has traditionally been used to describe code that is granted limited permissions, which is typically enforced by the security manager. However, many of these guidelines can also be applied to interactions with code from other classes, packages, modules, or libraries, even if the security manager is not being used. For example, it may be necessary to limit the visibility of classes or members to external code for security reasons, or to validate input passed by outside code before using it. Even if the external code itself is trusted, it may interact with untrusted users or data, which could make additional precautions and validation necessary. Developers should analyze the interactions that occur across an application's trust boundaries and identify the types of data involved to determine which guidelines are relevant for their code. Performing threat modeling and establishing trust boundaries can help to accomplish this (see Guideline 0-4). These guidelines are intended to help developers build secure software, but they do not focus specifically on software that implements security features. Therefore, topics such as cryptography are not covered in this document (see [9] and [10] for information on using cryptography with Java). While adding features to software can solve some security-related problems, it should not be relied upon to eliminate security defects. This document is periodically updated to cover features introduced in newer versions of Java SE, as well as to better describe best practices that apply to all Java SE versions. 0 FundamentalsThe following general principles apply throughout Java security. Guideline 0-0 / FUNDAMENTALS-0: Prefer to have obviously no flaws rather than no obvious flaws [8]Creating secure code is not necessarily easy. Despite the unusually robust nature of Java, flaws can slip past with surprising ease. Design and write code that does not require clever logic to see that it is safe. Specifically, follow the guidelines in this document unless there is a very strong reason not to. Guideline 0-1 / FUNDAMENTALS-1: Design APIs to avoid security concernsIt is better to design APIs with security in mind. Trying to retrofit security into an existing API is more difficult and error prone. For example, making a class final
prevents a malicious subclass from adding finalizers, cloning, and overriding random methods (Guideline 4-5). Any use of the Guideline 0-2 / FUNDAMENTALS-2: Avoid duplicationDuplication of code and data causes many problems. Both code and data tend not to be treated consistently when duplicated, e.g., changes may not be applied to all copies. Guideline 0-3 / FUNDAMENTALS-3: Restrict privilegesDespite best efforts, not all coding flaws will be eliminated even in well reviewed code. However, if the code is operating with reduced privileges, then exploitation of any flaws is likely to be thwarted. The most extreme form of this is known as the principle of least privilege, where code is run with the least privileges required to function. Low-level mechanisms available from operating systems or containers can be used to restrict privileges, and are recommended over higher-level mechanisms such as the Java security manager. Separate processes (JVMs) should be used to isolate untrusted code from trusted code with sensitive information. Applications can also be decomposed into separate services or processes to help restrict privileges. These services or processes can be granted different capabilities and OS-level permissions or even run on separate machines. Components of the application that require special permissions can be run separately with elevated privileges. Components that interact with untrusted code, users, or data can also be restricted or isolated, running with lower privileges. Separating parts of the application that require elevated privileges or that are more exposed to security threats can help to reduce the impact of security issues. The Java security mechanism can also be used to implement the principle of least privilege, although
it does not provide protection as strong as lower-level mechanisms. This can be implemented statically by restricting permissions through policy files and dynamically with the use of the Rich Internet Applications (RIA) can specify their requested permissions via an applet parameter or in the JNLP1. A signed JAR can also include a manifest attribute that specifies whether it must run in a sandbox or with all permissions (see [11]). If a sandboxed applet or application attempts to execute security-sensitive code, the JRE will throw a security exception. RIAs should follow the principle of least privilege, and should be configured to run with the least amount of necessary permissions. Running a RIA with all permissions should be avoided whenever possible. Guideline 0-4 / FUNDAMENTALS-4: Establish trust boundariesIn order to ensure that a system is protected, it is necessary to establish trust boundaries. Data that crosses these boundaries should be sanitized and validated before use. Trust boundaries are also necessary to allow security audits to be performed efficiently. Code that ensures integrity of trust boundaries must itself be loaded in such a way that its own integrity is assured. For instance, a web browser is outside of the system for a web server. Equally, a web server is outside of the system for a web browser. Therefore, web browser and server software should not rely upon the behavior of the other for security. When auditing trust boundaries, there are some questions that should be kept in mind. Are the code and data used sufficiently trusted? Could a library be replaced with a malicious implementation? Is untrusted configuration data being used? Is code calling with lower privileges adequately protected against? Guideline 0-5 / FUNDAMENTALS-5: Minimise the number of permission checksJava is primarily an object-capability language. Guideline 0-6 / FUNDAMENTALS-6: EncapsulateAllocate behaviors and provide succinct interfaces. Fields of objects should be private and accessors avoided. The interface of a method, class, package, and module should form a coherent set of behaviors, and no more. Guideline 0-7 / FUNDAMENTALS-7: Document security-related informationAPI documentation should cover security-related information such as required permissions, security-related exceptions, caller sensitivity (see Guidelines 9-8 through 9-11 for additional on this topic), and any preconditions or postconditions that are relevant to security. Furthermore, APIs should clearly document which checked exceptions are thrown, and, in the event an API chooses to throw unchecked exceptions to indicate domain-specific error conditions, should also document these unchecked exceptions, so that callers may handle them if desired. Documenting this information in comments for a tool such as Javadoc can also help to ensure that it is kept up to date. Guideline 0-8 / FUNDAMENTALS-8: Secure third-party codeLibraries, frameworks, and other third-party software can introduce security vulnerabilities and weaknesses, especially if they are not kept up to date. Security updates released by the author may take time to reach bundled applications, dependent libraries, or OS package management updates. Therefore, it is important to keep track of security updates for any third-party code being used, and make sure that the updates get applied in a timely manner. This includes both frameworks and libraries used by an application, as well as any dependencies of those libraries/frameworks. Dependency checking tools can help to reduce the effort required to perform these tasks, and can usually be integrated into the development and release process. It is also important to understand the security model and best practices for third-party software. Identify secure configuration options, any security-related tasks performed by the code (e.g. cryptographic functions or serialization), and any security considerations for APIs being used. Understanding past security issues and attack patterns against the code can also help to use it in a more secure manner. For example, if past security issues have applied to certain functionality or configurations, avoiding those may help to minimize exposure. Security considerations of third-party code should also be periodically revisited. In addition to applying security updates whenever they are released, more secure APIs or configuration options could be made available over time. 1 Denial of ServiceInput into a system should be checked so that it will not cause excessive resource consumption disproportionate to that used to request the service. Common affected resources are CPU cycles, memory, disk space, and file descriptors. In rare cases it may not be practical to ensure that the input is reasonable. It may be necessary to carefully combine the resource checking with the logic of processing the data. In addition to attacks that cause excessive resource consumption, attacks that result in persistent DoS, such as wasting significant disk space, need be defended against. Server systems should be especially robust against external attacks. Guideline 1-1 / DOS-1: Beware of activities that may use disproportionate resourcesExamples of attacks include:
Guideline 1-2 / DOS-2: Release resources in all casesSome objects, such as open files, locks and manually allocated memory, behave as resources which require every acquire operation to be paired with a definite release. It is easy to overlook the vast possibilities for executions paths when exceptions are thrown. Resources should always be released promptly no matter what. Even experienced programmers often handle resources incorrectly. In order to reduce errors, duplication should be minimized and resource handling concerns should be separated. The Execute Around Method pattern provides an excellent way of extracting the paired acquire and release operations. The pattern can be used concisely using the Java SE 8 lambda feature.
The try-with-resource syntax introduced in Java SE 7 automatically handles the release of many resource types.
For resources without support for the enhanced feature, use the standard resource acquisition and release. Attempts to rearrange this idiom typically result in errors and makes the code significantly harder to follow.
Ensure that any output buffers are flushed in the case that output was otherwise successful. If the flush fails, the code should exit via an exception.
Some decorators of resources may themselves be resources that require correct release. For instance, in the current Oracle JDK implementation compression-related streams are natively implemented using the C heap for buffer storage. Care must be taken that both resources are released in all circumstances.
Note, however, that in certain situations a try statement may never complete running (either normally or abruptly). For example, code inside of the try statement could indefinitely block while attempting to access a resource. If the try statement calls into other code, that code could also indefinitely sleep or block, preventing the cleanup code from being reached. As a result, resources used in a try-with-resources statement may not be closed, or code in a finally block may never be executed in these situations. Guideline 1-3 / DOS-3: Resource limit checks should not suffer from integer overflowThe Java language provides bounds checking on arrays which mitigates the vast majority of integer overflow attacks. However, some operations on primitive integral types silently overflow. Therefore, take care when checking resource limits. This is particularly important on persistent resources, such as disk space, where a reboot may not clear the problem. Some checking can be rearranged to avoid overflow. With large values,
If performance is not a particular issue, a verbose approach is to use arbitrary sized integers.
The
A peculiarity of two's complement integer arithmetic is that the minimum negative value does not have a matching positive value of the same magnitude. So, As of Java SE 8, the Guideline 1-4 / DOS-4: Implement Robust Error/Exceptions handling for servicesExceptions may occur for a number of reasons: bad inputs, logic errors, misconfiguration, environmental failures (e.g., network faults), and so forth. While it is best to prevent or avoid situations that cause exceptions in the first place, secure code should still assume that any exception may occur at any time. If a method call results in an exception, the caller must choose between handling or propagating the exception:
Only a few exceptions can be handled at the direct point of a call. It is generally acceptable for ordinary application and library code to propagate most exceptions, as the vast majority of error conditions cannot reasonably be handled by the caller. Code which acquires and holds resources which are not reclaimed by automatic memory management, such as explicit locks or native memory, should additionally release those resources before propagating exceptions to callers, as discussed in Guideline 1-2. It is the responsibility of a secure
system to define some policy for what should happen when an uncaught exception reaches the base of the call stack. Long-running systems tend to process discrete units of work, such as requests, events, tasks, etc., in a special part of the code that orchestrates the dispatching of these units of work. This code might start threads, enqueue events, send requests to handlers, and so forth. As such, it has a different responsibility from most other code. A reasonable policy for this orchestration
code is to handle a broad range of exceptions (typically catching The Java platform provides mechanisms to handle exceptions effectively, such as the 2 Confidential InformationConfidential data should be readable only within a limited context. Data that is to be trusted should not be exposed to tampering. Privileged code should not be executable through intended interfaces. Guideline 2-1 / CONFIDENTIAL-1: Purge sensitive information from exceptionsException objects may convey sensitive information. For example, if a method calls the Exposing a file path containing the current user's name or home directory exacerbates the problem. Internal exceptions should be caught and sanitized before propagating them to upstream callers. The type of an exception may reveal sensitive information,
even if the message has been removed. For instance, It is sometimes also necessary to sanitize exceptions containing information derived from caller inputs. For example, exceptions related to file access could disclose whether a file exists. An attacker may be able to gather useful information by providing various file names as input and analyzing the resulting exceptions. Be careful when depending on an exception for security because its contents may change in the future. Suppose a previous version of a library did not include a potentially sensitive piece of information in the exception, and an existing client relied upon that for security. For example, a library may throw an exception without a message. An application programmer may look at this behavior and decide that it is okay to propagate the exception. However, a later version of the library may add extra debugging information to the exception message. The application exposes this additional information, even though the application code itself may not have changed. Only include known, acceptable information from an exception rather than filtering out some elements of the exception. Exceptions may also include sensitive information about the configuration and internals of the system. Do not pass exception information to end users unless one knows exactly what it contains. For example, do not include exception stack traces inside HTML comments. Guideline 2-2 / CONFIDENTIAL-2: Do not log highly sensitive informationSome information, such as Social Security numbers (SSNs) and passwords, is highly sensitive. This information should not be kept for longer than necessary nor where it may be seen, even by administrators. For instance, it should not be sent to log files and its presence should not be detectable through searches. Some transient data may be kept in mutable data structures, such as char arrays, and cleared immediately after use. Clearing data structures has reduced effectiveness on typical Java runtime systems as objects are moved in memory transparently to the programmer. This guideline also has implications for implementation and use of lower-level libraries that do not have semantic knowledge of the data they are dealing with. As an example, a low-level string parsing library may log the text it works on. An application may parse an SSN with the library. This creates a situation where the SSNs are available to administrators with access to the log files. Guideline 2-3 / CONFIDENTIAL-3: Consider purging highly sensitive information from memory after useTo narrow the window when highly sensitive information may appear in core dumps, debugging, and confidentiality attacks, it may be appropriate to zero memory containing the data immediately after use rather than waiting for the garbage collection mechanism. However, doing so does have negative consequences. Code quality will be compromised with extra complications and mutable data structures. Libraries may make copies, leaving the data in memory anyway. The operation of the virtual machine and operating system may leave copies of the data in memory or even on disk. 3 Injection and InclusionA very common form of attack involves causing a particular program to interpret data crafted in such a way as to cause an unanticipated change of control. Typically, but not always, this involves text formats. Guideline 3-1 / INJECT-1: Generate valid formattingAttacks using maliciously crafted inputs to cause incorrect formatting of outputs are well-documented [7]. Such attacks generally involve exploiting special characters in an input string, incorrect escaping, or partial removal of special characters. If the input string has a particular format, combining correction and validation is highly error prone. Parsing and canonicalization should be done before validation. If possible, reject invalid data and any subsequent data, without attempting correction. For instance, many network protocols are vulnerable to cross-site POST attacks, by interpreting the HTTP body even though the HTTP header causes errors. Use well-tested libraries instead of ad hoc code. There are many libraries for creating XML. Creating XML documents using raw text is error-prone. For unusual formats where appropriate libraries do not exist, such as configuration files, create classes that cleanly handle all formatting and only formatting code. Guideline 3-2 / INJECT-2: Avoid dynamic SQLIt is well known that dynamically created SQL statements including untrusted input are subject to command injection. This often takes the form of supplying an input containing a quote character ( For parameterized SQL statements using Java Database Connectivity (JDBC), use An example of using PreparedStatement correctly:
Guideline 3-3 / INJECT-3: XML and HTML generation requires careUntrusted data should be properly sanitized before being included in HTML or XML output. Failure to properly sanitize the data can lead to many different security problems, such as Cross-Site Scripting (XSS) and XML Injection vulnerabilities. It is important to be particularly careful when using Java Server Pages (JSP). There are many ways to sanitize data before including it in output. Characters that are problematic for the specific type of output can be filtered, escaped, or encoded. Alternatively, characters that are known to be safe can be allowed, and everything else can be filtered, escaped, or encoded. This latter approach is preferable, as it does not require identifying and enumerating all characters that could potentially cause problems. Implementing correct data sanitization and encoding can be tricky and error prone. Therefore, it is better to use a library to perform these tasks during HTML or XML construction. Guideline 3-4 / INJECT-4: Avoid any untrusted data on the command lineWhen creating new processes, do not place any untrusted data on the command line.
Behavior is platform-specific, poorly documented, and frequently surprising. Malicious data may, for instance, cause a single argument to be interpreted as an option (typically a leading Guideline 3-5 / INJECT-5: Restrict XML inclusionXML Document Type Definitions (DTDs) allow URLs to be defined as system entities, such as local files and HTTP URLs within the local intranet or localhost. XML External Entity (XXE) attacks insert local files into XML data which may then be accessible to the client. Similar attacks may be made using XInclude, the XSLT document function, and the XSLT import and include elements. The safest way to avoid these problems while maintaining the power of XML is to reduce privileges (as described in Guideline 9-2) and to use the most restrictive configuration possible for the XML parser. Reducing privileges still allows you to grant some access, such as inclusion to pages from the same-origin web site if necessary. XML parsers can also be configured to limit functionality based on what is required, such as disallowing external entities or disabling DTDs altogether. Note that this issue generally applies to the use of APIs that use XML but are not specifically XML APIs. Guideline 3-6 / INJECT-6: Care with BMP filesBMP images files may contain references to local ICC (International Color Consortium) files. Whilst the contents of ICC files is unlikely to be interesting, the act of attempting to read files may be an issue. Either avoid BMP files, or reduce privileges as Guideline 9-2. Guideline 3-7 / INJECT-7: Disable HTML display in Swing componentsMany Swing pluggable look-and-feels interpret text in certain components starting with To disable the HTML render
feature, set the
Guideline 3-8 / INJECT-8: Take care interpreting untrusted codeCode can be hidden in a number of places. If the source is not trusted to supply code, then a secure sandbox must be constructed to run it in. Some examples of components or APIs that can potentially execute untrusted code include:
Guideline 3-9 / INJECT-9: Prevent injection of exceptional floating point valuesWorking with floating point numbers requires care when importing those from outside of a trust boundary, as
the NaN (not a number) or infinite values can be injected into applications via untrusted input data, for example by conversion of (untrusted) Strings converted by the Both positive and negative infinity values are possible outcomes of a floating point operation [2], when results become too high or too low to be representable by the memory area that backs a primitive floating point value. Also, the exceptional value NaN can result from dividing 0.0 by 0.0 or subtracting infinity from infinity. The results of casting propagated exceptional floating point numbers to short, integer and long primitive values need
special care, too. This is because an integer conversion of a NaN value will result in a 0, and a positive infinite value is transformed to There are distinct application scenarios where these exceptional values are expected, such as scientific data analysis which relies on numeric processing. However, it is advised that the result values be contained for that purpose in the local component. This can be achieved by sanitizing any floating point results before passing them back to the generic parts of an application. As mentioned before, the programmer may wish to include sanitization code for these exceptional values when working with floating point numbers, especially if related to authorization or authentication decisions, or forwarding floating point values to JNI. The A typical code pattern that can block further processing of unexpected floating point numbers is shown in the following example snippet. 4 Accessibility and ExtensibilityThe task of securing a system is made easier by reducing the "attack surface" of the code. Guideline 4-1 / EXTEND-1: Limit the accessibility of classes, interfaces, methods, and fieldsA Java package comprises a grouping of related Java classes and interfaces. Declare any class or interface public if it is specified as part of a published API, otherwise, declare it package-private. Similarly, declare class members and constructors (nested classes, methods, or fields) public or protected as appropriate, if they are also part of the API. Otherwise, declare them private or package-private to avoid exposing the implementation. Note that members of interfaces are implicitly public. Classes loaded by different loaders do not have package-private access to one another even if they have the same package name. Classes in the same package loaded by the same class loader must either share the same code signing certificate or not have a certificate at all. In the Java virtual machine class loaders are responsible for defining packages. It is recommended that, as a matter of course, packages are marked as sealed in the JAR file manifest. Guideline 4-2 / EXTEND-2: Use modules to hide internal packagesNote: The original content of this guideline has been moved to 9-16. A Java module is a set of packages designed for reuse. A module strongly encapsulates the classes and interfaces in its packages, except for the public classes and public interfaces in its exported packages. This means that code outside the module can access those public classes and public interfaces, but cannot access the classes and interfaces in other packages of the module even if they are public. In this way, packages which are not exported by a module are hidden from code outside the module. Declare a module so that packages which contain a published API are exported, and packages which support the implementation of the API are not exported. This ensures that implementation details of the API are strongly encapsulated. Examine all exported packages to be sure that no security-sensitive classes or interface have been exposed. Exporting additional packages in the future is easy but rescinding an export could cause compatibility issues. There are command line options to open / export specific packages beyond what the module configuration specifies. Minimizing the need for their usage is also recommended. Guideline 4-3 / EXTEND-3: Isolate unrelated codeContainers, that is to say code that manages code with a lower level of trust, should isolate unrelated application code. Even otherwise untrusted code is typically given permissions to access its origin, and therefore untrusted code from different origins should be isolated. The Java Plugin, for example, loads unrelated applets into separate class loader instances and runs them in separate thread groups.1 Although there may be security checks on direct accesses, there are indirect ways of using the system class loader and thread context class loader. Programs should be written with the expectation that the system class loader is accessible everywhere and the thread context class loader is accessible to all code that can execute on the relevant threads. Some apparently global objects are actually local to applet1 or application contexts. Applets loaded from different web sites will have
different values returned from, for example, Mutable statics (see Guideline 6-11) and exceptions are common ways that isolation is inadvertently breached. Mutable statics allow any code to interfere with code that directly or, more likely, indirectly uses them. Library code can be carefully written such that it is safely usable by less trusted code. Libraries require a level of trust at least equal to the code it is used by in order not to violate the integrity of the client code. Containers should ensure that less trusted code is not able to replace more trusted library code and does not have package-private access. Both restrictions are typically enforced by using a separate class loader instance, the library class loader a parent of the application class loader. Guideline 4-4 / EXTEND-4: Limit exposure of ClassLoader instancesAccess to
Guideline 9-8 explains access checks made on acquiring Guideline 4-5 / EXTEND-5: Limit the extensibility of classes and methodsDesign classes and methods for inheritance or declare them final [6]. Left non-final, a class or method may be overridden in a way that compromises security. A class that does not permit subclassing is easier to implement and verify that it is secure. Prefer composition to inheritance.
Malicious subclasses that override the
For compatibility with versions of Java prior to JDK 6, check that the class has been initialized before every sensitive operation and before trusting any other instance of the class. It may be possible to see a partially initialized instance, so any variable should have a safe interpretation for the default value. For mutable classes, it is advisable to make an "initialized" flag volatile to create a suitable happens-before relationship.
When confirming an object's class type by examining the Java SE 15 introduced sealed classes where code can limit which subclasses of a given class can exist. This can be used to prevent unauthorized implementations that may not follow the class contract. Guideline 4-6 / EXTEND-6: Understand how a superclass can affect subclass behaviorSubclasses do not have the ability to maintain absolute control over their own behavior. A superclass can affect subclass behavior by changing the implementation of an inherited method that is not overridden. If a subclass overrides all inherited methods, a superclass can still affect subclass behavior by introducing new methods. Such changes to a superclass can unintentionally break assumptions made in a subclass and lead to subtle security vulnerabilities. Consider the following example that occurred in JDK 1.2:
The class The The primary flaw is that the data belonging to Malicious subclasses may implement JDK 8 introduced default methods on interfaces. These default methods are another path for new and unexpected methods to show up in a class. If a class implements an interface with default methods, those are now part of the class and may allow unexpected access to internal data. For a security sensitive class, all interfaces implemented by the class (and all superclasses) would need to be monitored as previously discussed. 5 Input ValidationA feature of the culture of Java is that rigorous method parameter checking is used to improve robustness. More generally, validating external inputs is an important part of security. Guideline 5-1 / INPUT-1: Validate inputsInput from untrusted sources must be validated before use. Maliciously crafted inputs may cause problems, whether coming through method arguments or external streams. Examples include overflow of integer values and directory traversal attacks by including It may also be necessary to perform validation on input more than once. Performing validation early can be beneficial, as it will reject invalid input sooner and reduce exposure to malformed data. However, validating the input immediately prior to using it for a security-sensitive task will cover any modifications made since it was previously validated, and also allows for validation to be more specific to the context of its use. Earlier validation may not be effective for the current task, as it could have been performed by another part of the application or system, using different assumptions about the context or intended use of the input. Whenever possible, processing untrusted input should be avoided. For example, consuming a JAR file from an untrusted source might allow an attacker to inject malicious code or data into the system, causing misbehavior, excessive resource consumption, or other problems. Note that input validation must occur after any defensive copying of that input (see Guideline 6-2). Guideline 5-2 / INPUT-2: Validate output from untrusted objects as inputIn general method arguments should be validated but not return values. However, in the case of an upcall (invoking a method of higher level code) the returned value should be validated. Likewise, an object only reachable as an implementation of an upcall need not validate its inputs. A subtle example would be Guideline 5-3 / INPUT-3: Define wrappers around native methodsJava code is subject to runtime checks for type, array bounds, and library usage. Native code, on the other hand, is generally not. While pure Java code is effectively immune to traditional buffer overflow attacks, native methods are not. To offer some of these protections during the invocation of native code, do not declare a native method public. Instead, declare it private and expose the functionality through a public Java-based wrapper method. A wrapper can safely perform any necessary input validation prior to the invocation of the native method:
Guideline 5-4 / INPUT-4: Verify API behavior related to input validationDo not rely on an API for input validation without first verifying through documentation and testing that it performs necessary validation for the given context. For example, if documentation states that a class or method expects input to be in a specific syntax (e.g. according to a documented standard), do not assume that the called method/constructor will throw an exception if the input does not strictly adhere to that syntax, unless the documentation explicitly specifies that behavior. Verifying the API behavior is especially important when validating untrusted data. If a constructor (or method that returns an object) is relied upon to perform input validation, be sure to use the created/returned object and not the original input passed to it. Some constructors or methods may not outright reject invalid input, and may instead filter, escape, or encode the input used to construct the object. Therefore, even if the object has been safely constructed, the input may not be safe in its original form. Additionally, some classes may not validate the input until it is used, which may occur later (e.g. when a method is called on the created object). Additional steps may be required when using an API for input validation. It might be necessary to perform context-specific checks (such as range checks, allow/block list checks, etc.) in addition to the syntactic validation performed by the API. The caller may also need to sanitize certain data, such as meta-characters that identify macros or have other special meaning in the given context, prior to passing the data to the API. It may not be sufficient to use lower-level APIs for input validation, as they often provide additional flexibility that could be problematic in a higher-level application context. 6 MutabilityMutability, whilst appearing innocuous, can cause a surprising variety of security problems. The examples in this section use Guideline 6-1 / MUTABLE-1: Prefer immutability for value typesMaking classes immutable prevents the issues
associated with mutable objects (described in subsequent guidelines) from arising in client code. Immutable classes should not be subclassable. Further, hiding constructors allows more flexibility in instance creation and caching. This means making the constructor private or default access ("package-private"), or being in a package controlled by the Guideline 6-2 / MUTABLE-2: Create copies of mutable output valuesIf a method returns a reference to an internal mutable object, then client code may modify the internal state of the instance. Unless the intention is to share state, copy mutable objects and return the copy. To create a copy of a trusted mutable object, call a copy constructor or the clone method:
Guideline 6-3 / MUTABLE-3: Create safe copies of mutable and subclassable input valuesMutable objects may be changed after and even during the execution of a method or constructor call. Types that can be subclassed may behave incorrectly, inconsistently, and/or maliciously. If a method is not specified to operate directly on a mutable input parameter, create a copy of that input and perform the method logic on the copy. In fact, if the input is stored in a field, the caller can exploit race conditions in the enclosing class. For example, a time-of-check, time-of-use inconsistency (TOCTOU) [7] can be exploited where a mutable input contains one value during a security-related check but a different value when the input is used later. To create a copy of an untrusted mutable object, call a copy constructor or creation method:
In rare cases it may be safe to call a copy method on the instance itself. For instance,
It is safe to call This guideline does not apply to classes that are designed to wrap a target object. For instance, In some cases,
notably collections, a method may require a deeper copy of an input object than the one returned via that input's copy constructor or
Constructors should complete the deep copy before assigning values to a field. An object should never be in a state where it references untrusted data, even briefly. Further, objects assigned to fields should never have referenced untrusted data due to the dangers of unsafe publication. Guideline 6-4 / MUTABLE-4: Support copy functionality for a mutable classWhen designing a mutable value class, provide a means to create safe copies of its instances. This allows instances of that class to be safely passed to or returned from methods in other classes (see Guideline 6-2 and Guideline 6-3). This functionality may be provided by a static creation method, a copy constructor, or by implementing a public copy method (for final classes). If a class is final and does not provide an accessible method for acquiring a copy of it, callers could resort to performing a manual copy. This involves retrieving state from an instance of that class and then creating a new instance with the retrieved state. Mutable state retrieved during this process must likewise be copied if necessary. Performing such a manual copy can be fragile. If the class evolves to include additional state, then manual copies may not include that state. The Guideline 6-5 / MUTABLE-5: Do not trust identity equality when overridable on input reference objectsOverridable methods may not behave as expected. For instance, when expecting identity equality behavior, If possible, use a collection implementation that enforces identity equality, such as
If such a collection is not available, use a package private key which an adversary does not have access to.
Guideline 6-6 / MUTABLE-6: Treat passing input to untrusted object as outputThe above guidelines on output objects apply when passed to untrusted objects. Appropriate copying should be applied.
A common but difficult to spot case occurs when an input object is used as a key. A collection's use of equality may well expose other elements to a malicious input object on or after insertion. Guideline 6-7 / MUTABLE-7: Treat output from untrusted object as inputThe above guidelines on input objects apply when returned from untrusted objects. Appropriate copying and validation should be applied.
Guideline 6-8 / MUTABLE-8: Define wrapper methods around modifiable internal stateIf a state that is internal to a class must be publicly accessible and modifiable, declare a private field and enable access to it via public wrapper methods. If the state is only intended to be accessed by subclasses, declare a private field and enable access via protected wrapper methods. Wrapper methods allow input validation to occur prior to the setting of a new value:
Make additional defensive copies in Where possible make methods for operations that make sense in the context of the interface of the class rather than merely exposing internal implementation. Guideline 6-9 / MUTABLE-9: Make public static fields finalCallers can trivially access and modify public non-final static fields. Neither accesses nor modifications can be guarded against, and newly set values cannot be validated. Fields with subclassable types may be set to objects with unsafe or malicious implementations. Always declare public static fields as final.
If using an interface instead of a class, the modifiers " Protected static fields suffer from the same problem as their public equivalents but also tend to indicate confused design. Guideline 6-10 / MUTABLE-10: Ensure public static final field values are constantsOnly immutable or unmodifiable values should be stored in public static fields. Many types are mutable and are easily overlooked, in particular arrays and collections. Mutable objects that are stored in a field whose type does not have any mutator methods can be cast back to the runtime type. Enum values should never be mutable. In the following example, names exposes an unmodifiable view of a list in order to prevent the list from being modified.
The
Note that the The As per Guideline 6-9, protected static fields suffer from the same problems as their public equivalents. Guideline 6-11 / MUTABLE-11: Do not expose mutable staticsPrivate statics are easily exposed through public interfaces, if sometimes only in a limited way (see Guidelines 6-2 and 6-6). Mutable statics may also change behavior between unrelated code. To ensure safe code, private statics should be treated as if they are public. Adding boilerplate to expose statics as singletons does not fix these issues. Mutable statics may be used as caches of immutable flyweight values. Mutable objects should never be cached in statics. Even instance pooling of mutable objects should be treated with extreme caution. When a security manager is in place, some mutable statics require a security permission to update state. The updated value will be visible globally. Therefore mutation should be done with extreme care. Methods that update global state or provide a capability to do so, with a security check, include:
Java PlugIn and Java WebStart isolate certain global state within an
Guideline 6-12 / MUTABLE-12: Do not expose modifiable collectionsClasses that expose collections either through public variables or get methods have the potential for side effects, where calling classes can modify contents of the collection. Developers should consider exposing read-only copies of collections relating to security authentication or internal state. While modification of a field referencing a collection object can be prevented by declaring it In the following example, an unmodifiable collection is exposed via
Arrays exposed via public variables or get methods can introduce similar issues. For those cases, a copy of the internal array (created using Note that all of the collections in the previous example contain immutable objects. If a collection or array contains mutable objects, then it is necessary to expose a deep copy of it instead. See Guidelines 6-2 and 6-3 for additional information on creating safe copies. 7 Object ConstructionDuring construction objects are at an awkward stage where they exist but are not ready for use. Such awkwardness presents a few more difficulties in addition to those of ordinary methods. Guideline 7-1 / OBJECT-1: Avoid exposing constructors of sensitive classesConstruction of classes can be more carefully controlled if constructors are not exposed. Define static factory methods instead of public constructors. Support extensibility through delegation rather than inheritance. Implicit constructors through serialization and clone should also be avoided. Guideline 7-2 / OBJECT-2: Prevent the unauthorized construction of sensitive classesWhere an existing API exposes a security-sensitive constructor, limit the ability to create instances. A security-sensitive class enables callers to modify or circumvent To restrict untrusted code from instantiating a class, enforce a If the security-sensitive class is non-final, this guideline not only blocks the direct instantiation of that class, it blocks unsafe or malicious subclassing as well. Guideline 7-3 / OBJECT-3: Defend against partially initialized instances of non-final classesWhen a constructor in a non-final class throws an exception, attackers can attempt to gain access to partially initialized instances of that class. Ensure that a non-final class remains totally unusable until its constructor completes successfully. From JDK 6 on, construction of a subclassable class can be prevented by throwing an exception before the
For compatibility with older releases, a potential solution involves the use of an initialized flag. Set the flag as the last operation in a constructor before returning successfully. All methods providing a gateway to sensitive operations must first consult the flag before proceeding:
Furthermore, any security-sensitive uses of such classes should check the state of the initialization flag. In the case of Partially
initialized instances of a non-final class can be accessed via a finalizer attack. The attacker overrides the protected Use of an initialized flag, while
secure, can be cumbersome. Simply ensuring that all fields in a public non-final class contain a safe value (such as A more robust, but also more verbose, approach is to use a "pointer to implementation" (or "pimpl"). The core of the class is moved into a non-public class with the interface class forwarding method calls. Any attempts to use the
class before it is fully initialized will result in a
Guideline 7-4 / OBJECT-4: Prevent constructors from calling methods that can be overriddenConstructors that call overridable methods give attackers a reference to Guideline 7-5 / OBJECT-5: Defend against cloning of non-final classesA non-final class may be subclassed by a class that also implements 8 Serialization and DeserializationNote: Deserialization of untrusted data is inherently dangerous and should be avoided. Java Serialization provides an interface to classes that sidesteps the field access control mechanisms of the Java language. As a result, care must be taken when performing serialization and deserialization. Furthermore, deserialization of untrusted data should be avoided whenever possible, and should be performed carefully when it cannot be avoided (see 8-6 for additional information). This section covers serialization and deserialization performed by Java. While some of these guidelines are relevant for other serialization functionality provided by third-party libraries, it is important to consult the documentation and utilize best practices specific to third-party code as well. See Guideline 0-8 for additional information on security considerations for third-party code. Guideline 8-1 / SERIAL-1: Avoid serialization for security-sensitive classesSecurity-sensitive classes that are not serializable will not have the problems detailed in this section. Making a class serializable effectively creates a public interface to all fields of that class. Serialization also effectively adds a hidden public constructor to a class, which needs to be considered when trying to restrict object construction. Similarly, lambdas should be scrutinized before being made serializable. Functional interfaces should not be made serializable without due consideration for what could be exposed. It is also important to avoid unintentionally making a security-sensitive class serializable, either by subclassing a serializable class or implementing a serializable interface. Guideline 8-2 / SERIAL-2: Guard sensitive data during serializationOnce an object has been serialized the Java language's access controls can no longer be enforced and attackers can access private fields in an object by analyzing its serialized byte stream. Therefore, do not serialize sensitive data in a serializable class. Approaches for handling sensitive fields in serializable classes are:
Guideline 8-3 / SERIAL-3: View deserialization the same as object constructionDeserialization creates a new instance of a class without invoking any constructor on that class. Therefore, deserialization should be designed to behave like normal construction. Default deserialization and
Perform the same input validation
checks in a In addition create copies of deserialized mutable objects before assigning them to internal fields in a
Attackers can also craft hostile streams in an attempt to exploit partially initialized (deserialized) objects. Ensure a serializable class remains totally unusable until deserialization completes successfully. For example, use an Security-sensitive serializable classes should ensure that object field types are final classes, or do special validation to ensure exact
types when deserializing. Otherwise attacker code may populate the fields with malicious subclasses which behave in unexpected ways. For example, if a class has a field of type Guideline 8-4 / SERIAL-4: Duplicate the security-related checks performed in a class during serialization and deserializationPrevent an attacker from using serialization or deserialization to bypass
the security-related checks enforced in a class. Specifically, if a serializable class performs a security-related check in its constructors, then perform that same check in a
If a serializable class enables internal state to be modified by a caller (via a public method, for example) and the modification is guarded with a security-related
check, then perform that same check in a
If a serializable class enables internal state to be retrieved by a caller and the retrieval is guarded with a security-related check to prevent disclosure of sensitive data, then perform that same check in a
Guideline 8-5 / SERIAL-5: Understand the security permissions given to serialization and deserializationWhen a security manager is in place, permissions appropriate for deserialization should be carefully checked. Additionally, deserialization of untrusted data should generally be avoided whenever possible (regardless of whether a security manager is in place). Serialization with full permissions allows permission checks in Deserialization is more significant. A number of Guideline 8-6 / SERIAL-6: Filter untrusted serial dataSerialization Filtering is a new feature introduced in JDK 9 to improve both security and robustness when using Object Serialization. Security guidelines consistently require that input from external sources be validated before use; serialization filtering provides a mechanism to validate classes before they are deserialized.
Filters can be configured that apply to most uses of object deserialization without modifying the application. The filters are configured via system properties or configured using the override mechanism of the security properties. A typical use case is to create a block-list of classes that have been identified as potentially compromising the Java runtime. Using an allow-list of known safe classes is also straightforward (and preferred over a block-list approach for stronger security). When
taking the approach of blocking specific classes, it is important to consider that subclasses of the blocked class can still be deserialized. The filter mechanism allows object-serialization clients to more easily validate their inputs. For a more fine-grained approach the RMI supports the setting of serialization filters to protect remote invocations of exported objects. The RMI Registry and RMI distributed garbage collector use the filtering mechanisms defensively. Support for the configurable filters has been included in the CPU releases for JDK 8u121, JDK 7u131, and JDK 6u141. For more information and details please refer to [17] and [20]. 9 Access ControlAlthough Java is largely an object-capability language, a stack-based access control mechanism is used to securely provide more conventional APIs. Many of the guidelines in this section cover the use of the security manager to perform security checks, and to elevate or restrict permissions for code. Note that the security manager has been deprecated in Java 17 and will be removed in a future version3. See [24] for additional information. Also, the security manager does not and cannot provide protection against issues such as side-channel attacks or lower level problems such as Row hammer, nor can it guarantee complete intra-process isolation. Separate processes (JVMs) should be used to isolate untrusted code from trusted code with sensitive information. Utilizing lower level isolation mechanisms available from operating systems or containers is also recommended. Guideline 9-1 / ACCESS-1: Understand how permissions are checkedThe standard security check ensures that each frame in the call stack has the required permission. That is, the current permissions in force is the intersection of the permissions of each frame in the current access control context. If any frame does not have a permission, no matter where it lies in the stack, then the current context does not have that permission. Consider an application that indirectly uses secure operations through a library.
When the permission check is performed, the call stack will be as illustrated below.
In the above example, if the For library code to appear transparent to applications with respect to privileges, libraries should be granted permissions at least as generous as the application code that it is used with. For this reason, almost all the code shipped in the JDK and extensions is fully privileged. It is therefore important that there be at least one frame with the application's permissions on the stack whenever a library executes security checked operations on behalf of application code. Guideline 9-2 / ACCESS-2: Beware of callback methodsCallback methods are generally invoked from the system with full permissions. It seems reasonable to expect that malicious code needs to be on the stack in order to perform an operation, but that is not the case. Malicious code may set up objects that bridge the callback to a security checked operation. For instance, a file chooser dialog box that can manipulate the filesystem from user actions, may have events posted from malicious code. Alternatively, malicious code can disguise a file chooser as something benign while redirecting user events. Callbacks are widespread in object-oriented systems. Examples include the following:
This bridging between callback and security-sensitive operations is particularly tricky because it is not easy to spot the bug or to work out where it is. When implementing callback types, use the technique described in Guideline 9-6 to transfer context. Guideline 9-3 / ACCESS-3: Safely invoke java.security.AccessController.doPrivileged
In the above example, the privileges of the To avoid inadvertently performing such operations on behalf of unauthorized callers, be very careful when invoking
The implementation of It is also important to ensure that privileged operations do not leak sensitive information. Whenever the return value of Caller inputs that have been validated can sometimes be
safely used with Privileged code sections should be made as small as practical in order to make comprehension of the security implications tractable. By convention, instances of The two-argument overloads of
Guideline 9-4 / ACCESS-4: Know how to restrict privileges through doPrivilegedAs permissions are restricted to the intersection of frames, an artificial
All permissions can be removed using an artificial
An intermediate situation is possible where only a limited set of permissions is granted. If the permissions are checked in the current context before being supplied to
When granting permission to a directory, extreme care must be taken to ensure that the access does not have unintended consequences. Files or subdirectories could have insecure permissions, or filesystem objects could provide additional access outside of the directory (e.g. symbolic links, loop devices, network mounts/shares, etc.). It is important to consider this when granting file permissions via a security policy or Applications should utilize dedicated directories for code as well as for other filesystem use, and should ensure that secure permissions are applied. Running code from or granting access to shared/common directories (including access via symbolic links) should be avoided whenever possible. It is also recommended to configure file permission checking to be as strict and secure as possible [21]. A limited Consider the following example:
If a permission check matching the As with other versions of
Guideline 9-5 / ACCESS-5: Be careful caching results of potentially privileged operationsA cached result must never be passed to a context that does not have the relevant permissions to generate it. Therefore, ensure that the result is generated in a context that has no more permissions than any context it is returned to. Because
calculation of privileges may contain errors, use the
Guideline 9-6 / ACCESS-6: Understand how to transfer contextIt is often useful to store an access control context for later use. For example, one may decide it is appropriate to provide access to callback instances that perform privileged operations, but invoke callback methods in the context that the callback object was registered. The context may be restored later on in the same thread or in a different thread. A particular context may be restored multiple times and even after the original thread has exited.
Guideline 9-7 / ACCESS-7: Understand how thread construction transfers contextNewly constructed threads are executed
with the access control context that was present when the Guideline 9-8 / ACCESS-8: Safely invoke standard APIs that bypass SecurityManager checks depending on the immediate caller's class loaderCertain standard APIs in the core libraries of the Java runtime enforce The difference between this class loader comparison and a
Code has full access to its own class loader and any class loader that is a
descendant. In the case of In the diagram below, classes loaded by B have access to B and its descendants C, E, and D. Other class loaders, shown in grey strikeout font, are subject to security checks.
The following methods behave similar to
Methods such as these that vary their behavior according to the immediate caller's class are considered to be caller-sensitive, and should be annotated in code with the @CallerSensitive annotation [16]. Due to the security implications described here and in subsequent guidelines, making a method caller-sensitive should be avoided whenever possible. Refrain
from invoking the above methods on Guideline 9-9 / ACCESS-9: Safely invoke standard APIs that perform tasks using the immediate caller's class loader instanceThe following static methods perform tasks using the immediate caller's class loader:
Methods such as these that vary their behavior according to the immediate caller's class are considered to be caller-sensitive, and should be annotated in code with the @CallerSensitive annotation [16]. For example, Guideline 9-10 / ACCESS-10: Be aware of standard APIs that perform Java language access checks against the immediate callerWhen an object accesses fields or methods of another object, the JVM performs access control checks to assert the valid visibility of the target method or field. For example, it prevents objects from invoking private methods in other objects. Code may also call standard APIs (primarily in the
Methods such as these that vary their behavior according to the immediate caller's class are considered to be caller-sensitive, and should be annotated in code with the @CallerSensitive annotation [16]. Language checks are performed solely against the immediate caller, not
against each caller in the execution sequence. Because the immediate caller may have capabilities that other code lacks (it may belong to a particular package and therefore have access to its package-private members), do not invoke the above APIs on behalf of untrusted code. Specifically, do not invoke the above methods on Guideline 9-11 / ACCESS-11: Be aware java.lang.reflect.Method.invoke is ignored for checking the immediate callerConsider:
If
Therefore, avoid Guideline 9-12 / ACCESS-12: Avoid using caller-sensitive method names in interface classesWhen designing an interface class, one should avoid using methods with the same name and signature of caller-sensitive methods, such as those listed in Guidelines 9-8, 9-9, and 9-10. In particular, avoid calling these from default methods on an interface class. Guideline 9-13 / ACCESS-13: Avoid returning the results of privileged operationsCare should be taken when designing lambdas which are to be returned to untrusted code; especially ones that include security-related operations. Without proper precautions, e.g., input and output validation, untrusted code may be able to leverage the privileges of a lambda inappropriately. Similarly, care should be taken before returning Guideline 9-14 / ACCESS-14: Safely invoke standard APIs that perform tasks using the immediate caller's moduleThe following static methods perform tasks using the immediate caller's
Methods such as these that vary their behavior according to the immediate caller's class are considered to be caller-sensitive, and should be annotated in code with the @CallerSensitive annotation [16]. For example, Do not invoke any of these methods using inputs provided by untrusted code, and do not propagate objects that are returned by these methods back to untrusted code. Guideline 9-15 / ACCESS-15: Design and use InvocationHandlers conservativelyWhen creating a
Guideline 9-16 / ACCESS-16: Limit package accessibility with package.accessThe original content of this guideline that covers limiting package accessibility with modules can be found in 4-2. Containers (meaning code that manages code with a lower level of trust,
as described in Guideline 4-3) may hide implementation code by adding to the This example code demonstrates how to
append to the ConclusionThe Java Platform provides a robust basis for secure systems through features such as memory-safety. However, the platform alone cannot prevent flaws being introduced. This document details many of the common pitfalls. The most effective approach to minimizing vulnerabilities is to have obviously no flaws rather than no obvious flaws. References
Appendix A: Defensive use of the Java Native Interface (JNI)The Java Native Interface (JNI) is a standard programming interface for writing Java native methods and embedding a JVM into native applications [12] [13]. Native interfaces allow Java programs to interact with APIs that originally do not provide Java bindings. JNI supports implementing these wrappers in C, C++ or assembler. During runtime native methods defined in a dynamically loaded library are connected to a Java method declaration with the native keyword. JNI-1: Only use JNI when necessaryThe easiest security measure for JNI to remember is to avoid native code whenever possible. Therefore, the first task is to identify an alternative that is implemented in Java before choosing JNI as an implementation framework. This is mainly because the development chain of writing, deploying, and maintaining native libraries will burden the entire development chain for the lifetime of the component. Attackers like native code, mainly because JNI security falls back to the security of C/C++, therefore they expect it to break first when attacking a complex application. While it may not always be possible to avoid implementing native code, it should still be kept as short as possible to minimize the attack surface. JNI-2: Be aware of the C/C++ threat modelAlthough is it is not impossible to find exploitable holes in the Java layer, C/C++ coding flaws may provide attackers with a faster path towards exploitability. Native antipatterns enable memory exploits (such as heap and stack buffer overflows), but the Java runtime environment safely manages memory and performs automatic checks on access within array bounds. Furthermore, Java has no explicit pointer arithmetic. Native code requires dealing with heap resources carefully, which means that operations to allocate and free native memory require symmetry to prevent memory leaks. Proper heap management during runtime can be checked dynamically with heap checking tools. Depending on the runtime OS platform there may be different offerings (such as valgrind, guardmalloc or pageheap). JNI-3: Expect that JNI code can violate Java visibility and isolation rulesThe Java runtime environment sometimes executes untrusted code, and protection against access to unauthorized resources is a built-in feature. In C/C++, private resources such as files (containing passwords and private keys), system memory (private fields) and sockets are essentially just a pointer away. Existing code may contain vulnerabilities that could be instrumented by an attacker (on older operating systems simple shellcode injection was sufficient, whereas advanced memory protections would require the attacker to apply return-oriented programming techniques). This means that C/C++ code, once successfully loaded, is not limited by the Java's language access controls, visibility rules, or security policies3. The JRE does not block native code from registering native methods. This allows JNI libraries to redefine the bindings to the entire set of native methods. Programmers should be aware of this behavior. During development they are advised to perform security reviews and scans to check whether dependencies of their code introduce any security issues (see FUNDAMENTALS-8 for additional information about third-party code considerations). If any code running outside of the boot/platform loader tries rebinding native methods in classes loaded by the boot/platform loader, this may redirect the default control flows and by doing so subvert integrity of the entire JRE process. JNI-4: Secure your JNI implementation from the Java sideIn order to prevent native code from being exposed to untrusted and unvalidated data, Java code should sanitize data before passing it to JNI methods. This is also important for application scenarios that process untrusted persistent data, such as deserialization code. As stated in Guideline 5-3, native methods should be private and should only be accessed through Java-based wrapper methods. This allows for parameters to be validated by Java code before they are passed to native code. The following example illustrates how to validate a pair of offset and length values that are used when accessing a byte buffer. The Java-based wrapper method validates the values and checks for integer overflow before passing the values to a native method.
While this limits the propagation of maliciously crafted input which an attacker may use to overwrite native buffers, more aspects of the interaction between Java and JNI code require special care. Java hides memory management details like the heap object allocation via encapsulation, but the handling of native objects requires the knowledge of their absolute memory addresses. To prevent unsafe or malicious code from misusing operations on native objects to overwrite parts of memory, native operations should be designed without maintaining state. Stateless interaction may not always be possible. To prevent manipulation, native memory addresses kept on the Java side should be kept in private fields and treated as read-only from the Java side. Additionally, references to native memory should never be made accessible to untrusted code. JNI-5: Properly test JNI code for concurrent accessEspecially when maintaining state, be careful testing your JNI implementation so that it behaves stably in multi-threaded scenarios. Apply proper synchronization (prefer atomics to locks, minimize critical sections) to avoid race conditions when calling into the native layer. Concurrency-unaware code will cause memory corruption and other state inconsistency issues in and around the shared data sections. JNI-6: Secure library loadingThe JNI-7: Perform input validation at the language boundaryTo provide in-depth protection
against security issues with native memory access, the input passed from the Java layer requires revalidation on the native side. Using the runtime option Since values in C/C++ can be unsigned,
the native side should check for primitive parameters (especially array indices) to block negative values. Java code is also well protected against type-confusion. However, only a small number of types exist on the native side, and all user objects will be represented by instances of the JNI-8: Expect and handle exceptions when calling from JNI into JavaExceptions are an important construct of the Java language, because they help to distinguish between the normal control flow and any exceptional conditions that can occur during processing. This allows Java code to be prepared for conditions that cause failure. Native code has no direct support for Java exceptions, and any exceptions thrown by Java code will not affect the control flow of native code. Therefore, native code needs to explicitly check for exceptions after operations, especially when calling into Java methods that may throw exceptions. Exceptions may occur asynchronously, so it is necessary to check for exceptions in long native loops, especially when calling back into Java code. Be aware that many JNI API methods (e.g. Unexpected input and error conditions may cause native code to behave unpredictably. An input allow-list limits the exposure of JNI code to a set of expected values. JNI-9: Follow secure development practices for the native target platformModern operating systems provide a wide range of mechanisms that protect against the exploitability of common native programming bugs, such as stack buffer overflows and the various types of heap corruptions. Stack cookies protect against targeted overwrite of return addresses on the stack, which an attacker could otherwise use to divert control flow. Address Space Layout Randomization prevents attackers from placing formerly well-known return addresses on the stack, which when returning from a subroutine call systems code such as execve on the attacker's behalf. With the above protections, attackers may still choose to place native code snippets (shellcode) within the data heap, an attack vector that is prevented when the operating system allows to flag a memory page as Non-executable (NX). When building native libraries, some of the above techniques may not be enabled by default and may require an explicit opt-in by the library bootstrap code. In either case it is crucial to know and understand the secure development practice for a given operating system, and adapt the compile and build scripts accordingly [14][22][23]. Additionally, 32-/64-bit compatibility recommendations should be followed for the given operating system (e.g. [18]). Whenever possible, pure 64-bit builds should be used instead of relying on compatibility layers such as WOW. JNI-10: Ensure that bundled JVMs and JREs meet Java's secure baselinesNative applications may contain bundled JVMs and JREs for a variety of purposes. These may expose vulnerabilities over time due to software decay. System Administrators are responsible for running Java applications in a secure manner, following principle of least privilege, and staying up to date with Java’s secure baseline (either for standard Java SE or the Server JRE). Developers of applications containing an embedded JVM/JRE should also provide application updates to apply security fixes to the JVM/JRE. Previously unknown attack vectors can be eliminated by regularly updating the JRE/JDK with critical patch updates from Oracle Technical Network [19]. To keep updates as easy as possible vendors should minimize or even better avoid customization of files in the JRE directory. Endnotes
Why Oracle
Learn
What’s New
Which of the following attributes can serve as a useful factors for coding lessons learned?Any of the following attributes can serve as a useful factor for coding lessons learnedEXCEPT:type of project.
Which of the following is true concerning lesson learned on a project?Which of the following is true concerning lessons learned on a project? Lessons are the knowledge gained by team members as they perform the project.
When the project may be completed early with some parts of the project eliminated this is considered?2) In premature project closure, the project may be completed early with some parts of the project eliminated.
What should be done with any activities that remain incomplete at the time of project closure quizlet?What should be done with any activities that remain incomplete at the time of project closure? A punch it list should be made with any activities that remain incomplete at the time of the project closure.
|