Which of the following is a primary vector for attacking applications that will cause these applications to behave in an unexpected way when passing invalid data?

  • Click to view our Accessibility Policy
  • Skip to content

  • Java
  • Technical Details
  • Java SE

Secure Coding Guidelines for Java SE

Document version: 9.0
Last updated: January 2022

  • Introduction
  • 0 Fundamentals
  • 1 Denial of Service
  • 2 Confidential Information
  • 3 Injection and Inclusion
  • 4 Accessibility and Extensibility
  • 5 Input Validation
  • 6 Mutability
  • 7 Object Construction
  • 8 Serialization and Deserialization
  • 9 Access Control
  • Conclusion
  • References
  • Appendix A: Defensive use of the JNI

Introduction

Java'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 Fundamentals

The 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 concerns

It 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 SecurityManager highlights an area that should be scrutinized.

Guideline 0-2 / FUNDAMENTALS-2: Avoid duplication

Duplication 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 privileges

Despite 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 java.security.AccessController.doPrivileged mechanism [see Section 9]. Note that when taking this approach, the security manager should be installed as early as possible [ideally from the command-line]. Delaying installation may result in security-sensitive operations being performed before the security manager is in place, which could reduce the effectiveness of security checks or cause objects to be created with excessive permissions.

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 boundaries

In 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 checks

Java is primarily an object-capability language. SecurityManager checks should be considered a last resort. Perform security checks at a few defined points and return an object [a capability] that client code retains so that no further permission checks are required. Note, however, that care must be taken by both the code performing the check and the caller to prevent the capability from being leaked to code without the proper permissions. See Section 9 for additional information.

Guideline 0-6 / FUNDAMENTALS-6: Encapsulate

Allocate 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 information

API 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 code

Libraries, 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 Service

Input 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 resources

Examples of attacks include:

  • Requesting a large image size for vector graphics. For instance, SVG and font files.
  • Integer overflow errors can cause sanity checking of sizes to fail.
  • An object graph constructed by parsing a text or binary stream may have memory requirements many times that of the original data.
  • "Zip bombs" whereby a short file is very highly compressed. For instance, ZIPs, GIFs and gzip encoded HTTP contents. When decompressing files, it is better to set limits on the decompressed data size rather than relying upon compressed size or meta-data.
  • "Billion laughs attack" whereby XML entity expansion causes an XML document to grow dramatically during parsing. Set the XMLConstants.FEATURE_SECURE_PROCESSING feature to enforce reasonable limits.
  • Causing many keys to be inserted into a hash table with the same hash code, turning an algorithm of around O[n] into O[n2].
  • Regular expressions may exhibit catastrophic backtracking.
  • XPath expressions may consume arbitrary amounts of processor time.
  • Java deserialization and Java Beans XML deserialization of malicious data may result in unbounded memory or CPU usage.
  • Detailed logging of unusual behavior may result in excessive output to log files.
  • Infinite loops can be caused by parsing some corner case data. Ensure that each iteration of a loop makes some progress.
  • Processing JARs from untrusted sources may lead to resource exhaustion and/or unexpected runtime behavior.

Guideline 1-2 / DOS-2: Release resources in all cases

Some 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.

long sum = readFileBuffered[InputStream in -> { long current = 0; for [;;] { int b = in.read[]; if [b == -1] { return current; } current += b; } }];

The try-with-resource syntax introduced in Java SE 7 automatically handles the release of many resource types.

public R readFileBuffered[ InputStreamHandler handler ] throws IOException { try [final InputStream in = Files.newInputStream[path]] { handler.handle[new BufferedInputStream[in]]; } }

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.

public R locked[Action action] { lock.lock[]; try { return action.run[]; } finally { lock.unlock[]; } }

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.

public void writeFile[ OutputStreamHandler handler ] throws IOException { try [final OutputStream rawOut = Files.newOutputStream[path]] { final BufferedOutputStream out = new BufferedOutputStream[rawOut]; handler.handle[out]; out.flush[]; } }

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.

public void bufferedWriteGzipFile[ OutputStreamHandler handler ] throws IOException { try [ final OutputStream rawOut = Files.newOutputStream[path]; final OutputStream compressedOut = new GzipOutputStream[rawOut]; ] { final BufferedOutputStream out = new BufferedOutputStream[compressedOut]; handler.handle[out]; out.flush[]; } }

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 overflow

The 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, current + extra could overflow to a negative value, which would always be less than max.

private void checkGrowBy[long extra] { if [extra < 0 || current > max - extra] { throw new IllegalArgumentException[]; } }

If performance is not a particular issue, a verbose approach is to use arbitrary sized integers.

private void checkGrowBy[long extra] { BigInteger currentBig = BigInteger.valueOf[current]; BigInteger maxBig = BigInteger.valueOf[max]; BigInteger extraBig = BigInteger.valueOf[extra]; if [extra < 0 || currentBig.add[extraBig].compareTo[maxBig] > 0] { throw new IllegalArgumentException[]; } }

The checkIndex, checkFromToIndex, and checkFromIndexSize methods from the java.util.Objects class [available in Java 9 and later] can also be used to avoid integer overflows when performing range and bounds checks. These methods throw an IndexOutOfBoundsException if the index or sub-range being checked is out of bounds. The following code from java.io.OutputStream demonstrates this:

public void write[byte b[], int off, int len] throws IOException { Objects.checkFromIndexSize[off, len, b.length]; // len == 0 condition implicitly handled by loop bounds for [int i = 0 ; i < len ; i++] { write[b[off + i]]; } }

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, Integer.MIN_VALUE == -Integer.MIN_VALUE, Integer.MIN_VALUE == Math.abs[Integer.MIN_VALUE] and, for integer a, a < 0 does not imply -a > 0. The same edge case occurs for Long.MIN_VALUE.

As of Java SE 8, the java.lang.Math class also contains methods for various operations [addExact, multiplyExact, decrementExact, etc.] that throw an ArithmeticException if the result overflows the given type.

Guideline 1-4 / DOS-4: Implement Robust Error/Exceptions handling for services

Exceptions 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:

  • Handling an exception means catching it, possibly performing some corrective, cleanup, or fallback action, and then proceeding normally so that the caller's own caller is shielded from the error condition.
  • Propagating the exception exposes the error condition to the caller's own caller, granting it the choice to handle or propagate. Propagation may involve catching, wrapping, and rethrowing the exception, or may involve no explicit action; in either case, the runtime unwinds the current call frame and delegates to the caller's own caller.

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 Throwable] by discarding the current unit of work, logging the issue, performing some cleanup action, and dispatching the next unit of work. Of course, many different policies are reasonable and appropriate, depending upon the purpose of the system. In very rare circumstances, an error condition may leave the runtime in a state from which it is impossible or infeasible to continue safely to the next unit of work; in such cases, the system should exit [and ideally, arrange to be restarted.]

The Java platform provides mechanisms to handle exceptions effectively, such as the try-catch-finally statement of the Java programming language, and, as a last resort, the Thread.UncaughtExceptionHandler mechanism for consistent handling of uncaught exceptions across a framework. Secure systems need to make effective use of these mechanisms in order to achieve their desired quality, security, and robustness goals. It is important for applications to minimize exceptions by utilizing robust resource management, and also by eliminating bugs that could result in exceptions being thrown. However, since exceptions may also be thrown due to unforeseeable or unavoidable conditions, secure systems must also be able to safely handle exceptions whenever possible.


2 Confidential Information

Confidential 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 exceptions

Exception objects may convey sensitive information. For example, if a method calls the java.io.FileInputStream constructor to read an underlying configuration file and that file is not present, a java.io.FileNotFoundException containing the file path is thrown. Propagating this exception back to the method caller exposes the layout of the file system. Many forms of attack require knowing or guessing locations of files.

Exposing a file path containing the current user's name or home directory exacerbates the problem. SecurityManager checks guard this information when it is included in standard system properties [such as user.home] and revealing it in exception messages effectively allows these checks to be bypassed.

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, FileNotFoundException reveals whether a given file exists.

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 information

Some 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 use

To 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 Inclusion

A 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 formatting

Attacks 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 SQL

It 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 ['] followed by SQL. Avoid dynamic SQL.

For parameterized SQL statements using Java Database Connectivity [JDBC], use java.sql.PreparedStatement or java.sql.CallableStatement instead of java.sql.Statement. In general, it is better to use a well-written, higher-level library to insulate application code from SQL. When using such a library, it is not necessary to limit characters such as quote [']. If text destined for XML/HTML is handled correctly during output [Guideline 3-3], then it is unnecessary to disallow characters such as less than [ data.length ] { throw new IllegalArgumentException[]; } nativeOperation[data, offset, len]; } }

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 access

Especially 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 loading

The System.loadLibrary["/com/foo/MyLib.so"] method uses the immediate caller's class loader to find and load the specified native library. Loading libraries enables a caller to invoke native methods. Therefore, do not invoke loadLibrary in a trusted library on behalf of untrusted code, since untrusted code may not have the ability to load the same library using its own class loader instance [see Guidelines 9-8 and 9-9 for additional information]. Avoid placing a loadLibrary call in a privileged block, as this would allow untrusted callers to directly trigger native library initializations. Instead, require a policy with the loadLibrary permission granted. As mentioned earlier, parameter validation should also be performed, and loadLibrary should not be invoked using input provided by untrusted code. Objects that are returned by native methods should not be handed back to untrusted code.

JNI-7: Perform input validation at the language boundary

To 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 -Xcheck:jni can be helpful catching those issues, which can be fatal to an application, such as passing illegal references, or mixing up array types with non-array types. This option will not protect against subtle semantic conversion errors that can occur on the boundary between native code and Java.

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 jobject type.

JNI-8: Expect and handle exceptions when calling from JNI into Java

Exceptions 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. GetFieldID] can return NULL or an error code when an exception is thrown. Native code frequently needs to return error values and the calling Java method should be prepared to handle such error conditions accordingly.

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 platform

Modern 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 baselines

Native 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

  1. Java Applet and WebStart functionality was deprecated in Java 9 and removed in Java 11.
  2. This method has been deprecated.
  3. The security manager has been deprecated in Java 17 and will be removed in a future release. See [24] for details.

Why Oracle

  • Analyst Reports
  • Best cloud-based ERP
  • Cloud Economics
  • Corporate Responsibility
  • Diversity and Inclusion
  • Security Practices

Learn

  • What is cloud computing?
  • What is CRM?
  • What is Docker?
  • What is Kubernetes?
  • What is Python?
  • What is SaaS?

What’s New

  • News
  • Oracle CloudWorld
  • Oracle Supports Ukraine
  • Oracle Red Bull Racing
  • Oracle Sustainability
  • Employee Experience Platform

    • © 2022 Oracle
    • Privacy/Do Not Sell My Info
    • Ad Choices
    • Careers
    • Facebook
    • Twitter
    • LinkedIn
    • YouTube

    Which of the following security attacks occurs when an attacker exploits a known vulnerability in an application which could cause another application to crash?

    A buffer overflow attack occurs when an attacker exploits a known vulnerability in an application [for example, an error in an application that allowed that application to write to an area of memory [that is, a buffer] dedicated to a different application], which could cause another application to crash.

    Which of the given XSS attacks exploits a vulnerability on the client side?

    Reflected and stored XSS attacks exploit server-side scripts, while the DOM is used to exploit vulnerabilities in client-side scripts.

    What is a vulnerability that is exploited before the developer knows about it or can release a patch?

    A zero-day attack is a software-related attack that exploits a weakness that a vendor or developer was unaware of. The solution to fixing a zero-day attack is known as a software patch. Zero-day attacks can be prevented, though not always, through antivirus software and regular system updates.

    What vulnerability occurs when the output of an event depends on ordered or timed outputs?

    Race conditions – This vulnerability is when the output of an event depends on ordered or timed outputs. A race condition becomes a source of vulnerability when the required ordered or timed events do not occur in the correct order or proper timing.

    Bài Viết Liên Quan

    Chủ Đề