Top Qs
Timeline
Chat
Perspective

Security of the Java software platform

Security for the Java platform and its applications From Wikipedia, the free encyclopedia

Remove ads

The Java software platform provides a number of features designed for improving the security of Java applications. This includes enforcing runtime constraints through the use of the Java Virtual Machine (JVM), a security manager that sandboxes untrusted code from the rest of the operating system, and a suite of security APIs that Java developers can utilise. Despite this, criticism has been directed at the programming language, and Oracle, due to an increase in malicious programs that revealed security vulnerabilities in the JVM, which were subsequently not properly addressed by Oracle in a timely manner.

Remove ads

Security features

Summarize
Perspective

The JVM

The binary form of programs running on the Java platform is not native machine code but an intermediate bytecode. The JVM performs verification on this bytecode before running it to prevent the program from performing unsafe operations such as branching to incorrect locations, which may contain data rather than instructions. It also allows the JVM to enforce runtime constraints such as array bounds checking. This means that Java programs are significantly less likely to suffer from memory safety flaws such as buffer overflow than programs written in languages such as C which do not provide such memory safety guarantees.

The platform does not allow programs to perform certain potentially unsafe operations such as pointer arithmetic or unchecked type casts. It manages memory allocation and initialization and provides automatic garbage collection which in many cases (but not all) relieves the developer from manual memory management. This contributes to type safety and memory safety.

Security manager

The platform provides a security manager which allows users to run untrusted bytecode in a "sandboxed" environment designed to protect them from malicious or poorly written software by preventing the untrusted code from accessing certain platform features and APIs. For example, untrusted code might be prevented from reading or writing files on the local filesystem, running arbitrary commands with the current user's privileges, accessing communication networks, accessing the internal private state of objects using reflection, or causing the JVM to exit.

The security manager also allows Java programs to be cryptographically signed; users can choose to allow code with a valid digital signature from a trusted entity to run with full privileges in circumstances where it would otherwise be untrusted.

Users can also set fine-grained access control policies for programs from different sources. For example, a user may decide that only system classes should be fully trusted, that code from certain trusted entities may be allowed to read certain specific files, and that all other code should be fully sandboxed.

Security APIs

The Java Class Library provides a number of APIs related to security, such as standard cryptographic algorithms, authentication, and secure communication protocols.

The sun.misc.Unsafe class

sun.misc.Unsafe is an internal utility class in the Java programming language which is a collection of low-level unsafe operations.[1] While it is not a part of the official Java Class Library, it is called internally by the Java libraries. It resides in an unofficial Java module named jdk.unsupported. Beginning in Java 11, it has been partially migrated to jdk.internal.misc.Unsafe (which resides in module java.base).[1]

Its primary feature is to allow direct memory management (similar to C memory management) and memory address manipulation, manipulating objects and fields, thread manipulation, and concurrency primitives.

Its declaration is: public final class Unsafe;, and it is a singleton class with a private constructor.[2]

It contains the following methods, many of which are declared native (invoking Java Native Interface):[2][3]

  • static Unsafe getUnsafe() : retrieves the Unsafe instance. It uses sun.reflect.Reflection to do so.
  • int getInt(Object o, long offset) : fetches a value (a field or array element) in the object at the given offset. (There are corresponding getBoolean(), getByte(), getShort(), getChar(), getLong(), getFloat(), and getDouble() methods as well.)
  • void putInt(Object o, long offset, int x) : stores a value into an object at the given offset. (There are corresponding putBoolean(), putByte(), putShort(), putChar(), putLong(), putFloat(), and putDouble() methods as well.)
  • Object getObject(Object o, long offset) : fetches a reference value from an object at the given offset.
  • void putObject(Object o, long offset, Object x) : stores a reference value into an object at the given offset.
  • int getInt(long address) : fetches a value at the given address. (There are corresponding getBoolean(), getByte(), getShort(), getChar(), getLong(), getFloat(), and getDouble() methods as well.)
  • void putInt(long address, int x) : stores a value into the given address. (There are corresponding putBoolean(), putByte(), putShort(), putChar(), putLong(), putFloat(), and putDouble() methods as well.)
  • long getAddress(long address) : fetches a native pointer from a given address.
  • void putAddress(long address, long x) : stores a native pointer into a given address.
  • long allocateMemory(long bytes) : allocates a block of native memory of the given size (similar to malloc()).
  • long reallocateMemory(long address, long bytes) : resizes a block of native memory to the given size (similar to realloc()).
  • void setMemory(Object o, long offset, long bytes, byte value) , void setMemory(long address, long bytes, byte value) : sets all bytes in a block of memory to a fixed value (similar to memset()).
  • void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) , void copyMemory(long srcAddress, long destAddress, long bytes) : sets all bytes in a given block of memory to a copy of another block (smilar to memcpy()).
  • void freeMemory(long address) : deallocates a block of native memory obtained from allocateMemory() or reallocateMemory(), similar to free()).
  • long staticFieldOffset(Field f) : obtains the location of a given field in the storage allocation of its class.
  • long objectFieldOffset(Field f) : obtains the location of a given static field in conjunction with staticFieldBase().
  • Object staticFieldBase(Field f) : obtains the location of a given static field in conjunction with staticFieldOffset().
  • void ensureClassInitialized(Class<?> c) : ensures the given class has been initialized.
  • int arrayBaseOffset(Class<?> arrayClass) : obtains the offset of the first element in the storage allocation of a given array class.
  • int arrayIndexScale(Class<?> arrayClass) : obtains the scale factor for addressing elements in the storage allocation of a given array class.
  • static int addressSize() : obtains the size (in bytes) of a native pointer.
  • int pageSize() : obtains the size (in bytes) of a native memory page.
  • Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain) : signals to the JVM to define a class without security checks.
  • Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) : signals to the JVM to define a class but do not make it known to the class loader or system directory.
  • Object allocateInstance(Class<?> cls) throws InstantiationException : allocates an instance of a class without running its constructor.
  • void monitorEnter(Object o) : locks an object.
  • void monitorExit(Object o) : unlocks an object.
  • boolean tryMonitorEnter(Object o) : tries to lock an object, returning whether the lock succeeded.
  • void throwException(Throwable ee) : throws an exception without telling the verifier.
  • final boolean compareAndSwapInt(Object o, long offset, int expected, int x) : updates a variable to x if it is holding expected, returning whether the operation succeeded. (There are corresponding compareAndSwapLong() and compareAndSwapObject() methods as well.)
  • int getIntVolatile(Object o, long offset) : volatile version of getInt(). (There are corresponding getBooleanVolatile(), getByteVolatile(), getShortVolatile(), getCharVolatile(), getLongVolatile(), getFloatVolatile(), getDoubleVolatile(), and getObjectVolatile() methods as well.)
  • void putIntVolatile(Object o, long offset, int x) : volatile version of putInt(). (There are corresponding putBooleanVolatile(), putByteVolatile(), putShortVolatile(), putCharVolatile(), putLongVolatile(), putFloatVolatile(), putDoubleVolatile(), and putObjectVolatile() methods as well.)
  • void putOrderedInt(Object o, long offset, int x) : version of putIntVolatile() not guaranteeing immediate visibility of storage to other threads. (There are corresponding putOrderedLong() and putOrderedObject() methods as well.)
  • void unpark(Object thread) : unblocks a thread.
  • void park(boolean isAbsolute, long time) : blocks the current thread.
  • int getLoadAverage(double[] loadavg, int nelems) : gets the load average in the system run queue assigned to available processors averaged over various periods of time.
  • void invokeCleaner(ByteBuffer directBuffer) : invokes the given direct byte buffer's cleaner.
  • void fullFence() : ensures loads and stores before the fence will not be reordered with loads and stores after the fence.
  • void loadFence() : ensures loads before the fence will not be reordered with loads and stores after the fence.
  • void storeFence() : ensures loads and stores before the fence will not be reordered with stores after the fence.

it also contains the following constants:

  • static final int INVALID_FIELD_OFFSET = -1
  • static final int ARRAY_BOOLEAN_BASE_OFFSET = arrayBaseOffset(boolean[].class)
  • static final int ARRAY_BYTE_BASE_OFFSET = arrayBaseOffset(byte[].class)
  • static final int ARRAY_SHORT_BASE_OFFSET = arrayBaseOffset(short[].class)
  • static final int ARRAY_CHAR_BASE_OFFSET = arrayBaseOffset(char[].class)
  • static final int ARRAY_INT_BASE_OFFSET = arrayBaseOffset(int[].class)
  • static final int ARRAY_LONG_BASE_OFFSET = arrayBaseOffset(long[].class)
  • static final int ARRAY_FLOAT_BASE_OFFSET = arrayBaseOffset(float[].class)
  • static final int ARRAY_DOUBLE_BASE_OFFSET = arrayBaseOffset(double[].class)
  • static final int ARRAY_OBJECT_BASE_OFFSET = arrayBaseOffset(Object[].class)
  • static final int ARRAY_BOOLEAN_INDEX_SCALE = arrayIndexScale(boolean[].class)
  • static final int ARRAY_BYTE_INDEX_SCALE = arrayIndexScale(byte[].class)
  • static final int ARRAY_SHORT_INDEX_SCALE = arrayIndexScale(short[].class)
  • static final int ARRAY_CHAR_INDEX_SCALE = arrayIndexScale(char[].class)
  • static final int ARRAY_INT_INDEX_SCALE = arrayIndexScale(int[].class)
  • static final int ARRAY_LONG_INDEX_SCALE = arrayIndexScale(long[].class)
  • static final int ARRAY_FLOAT_INDEX_SCALE = arrayIndexScale(float[].class)
  • static final int ARRAY_DOUBLE_INDEX_SCALE = arrayIndexScale(double[].class)
  • static final int ARRAY_OBJECT_INDEX_SCALE = arrayIndexScale(Object[].class)
  • static final int ADDRESS_SIZE = addressSize()

Examples

An example usage the following:

package org.wikipedia.example;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Example {
    public static void main(String[] args) throws Exception {
        // Get Unsafe instance via reflection
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe)f.get(null);

        // Allocate a block of 8 bytes
        long memoryAddress = unsafe.allocateMemory(8L);

        try {
            // Insert a long into the memory, and read from that block
            unsafe.putLong(memoryAddress, 123456789L);
            long value = unsafe.getLong(memoryAddress);
            System.out.printf("Value from memory: %d%n", value); // Output: 123456789
        } finally {
            // Free the allocated memory
            unsafe.freeMemory(memoryAddress);
        }
    }
}

One can also wrap native memory segments, like java.lang.foreign.MemorySegment:

package org.wikipedia.example;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class NativeMemory implements AutoCloseable {
    private static final Unsafe unsafe;
    private final long address;
    private final long size;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe)theUnsafe.get(null);
        } catch (Exception e) {
            throw new RuntimeException("Unable to access Unsafe", e);
        }
    }

    public NativeMemory(long size) {
        this.size = size;
        this.address = unsafe.allocateMemory(size);
    }

    public void putByte(long offset, byte value) {
        checkBounds(offset, 1);
        unsafe.putByte(address + offset, value);
    }

    public byte getByte(long offset) {
        checkBounds(offset, 1);
        return unsafe.getByte(address + offset);
    }

    private void checkBounds(long offset, long bytes) {
        if (offset < 0 || offset + bytes > size) {
            throw new IndexOutOfBoundsException(String.format("Offset out of bounds: %d", offset));
        }
    }

    @Override
    public void close() {
        unsafe.freeMemory(address);
    }
}

In use:

package org.wikipedia.example;

public class Main {
    public static void main(String[] args) {
        try (NativeMemory mem = new NativeMemory(1024)) {
            mem.putByte(0, (byte)42);
            System.out.printf("Value: %s%n", mem.getByte(0));
        }
    }
}
Remove ads

Potential sources of security vulnerabilities in Java applications

Summarize
Perspective

There are a number of possible sources of security vulnerabilities in Java applications, some of which are common to non-Java applications and some of which are specific to the Java platform. (Note that these refer to potential sources of vulnerabilities which need to be kept in mind by security-conscious programmers: this is not intended as a list of actual vulnerabilities.)

Examples of potential sources of vulnerability common to Java and non-Java applications are:

  • Vulnerabilities in the protection mechanisms provided by the hardware or operating system which the application relies upon for its security
  • Vulnerabilities in native libraries, such as the C standard library, which may be used to implement the application and/or runtime
  • Vulnerabilities caused purely by errors in user programs (for example improper construction of SQL queries leading to SQL injection vulnerabilities)

However, much discussion of Java security focusses on potential sources of vulnerability specific to the Java platform. These include:

  • Vulnerabilities in the sandboxing mechanism which allow untrusted bytecode to circumvent the restrictions imposed by the security manager
  • Vulnerabilities in the Java class library which an application relies upon for its security

A vulnerability in the Java platform will not necessarily make all Java applications vulnerable. When vulnerabilities and patches are announced, for example by Oracle, the announcement will normally contain a breakdown of which types of application are affected (example).

For example, a hypothetical security flaw which affects only the security manager sandboxing mechanism of a particular JVM implementation would mean that only Java applications which run arbitrary untrusted bytecode would be compromised: applications where the user fully trusts and controls all bytecode being executed would not. This would mean that, say, a web browser plugin based on that JVM would be vulnerable to malicious applets downloaded from public websites, but a server-side web application running on the same version of the JVM where the administrator has full control over the classpath would be unaffected.[4] As with non-Java applications, security vulnerabilities can stem from parts of the platform which may not initially appear to be security-related. For example, in 2011, Oracle issued a security fix for a bug in the Double.parseDouble method.[5] This method converts a string such as "12.34" into the equivalent double-precision floating point number. The bug caused this method to enter an infinite loop when called on a specific input. This bug had security implications, because for example if a web server converts a string typed into a form by the user using this method, a malicious user could type in the string which triggers the bug. This would cause the web server thread processing the malicious request to enter an infinite loop and become unavailable for serving requests from other users. Doing this repeatedly to a vulnerable web server would be an easy denial-of-service attack: all the web server's threads for responding to user requests would soon be stuck in the infinite loop and the web server would be unable to serve any legitimate users at all.

Remove ads

Criticism of security manager

Summarize
Perspective

The security manager in the Java platform (which, as mentioned above, is designed to allow the user to safely run untrusted bytecode) has been criticized in recent years for making users vulnerable to malware, especially in web browser plugins which execute Java applets downloaded from public websites, more informally known as "Java in the browser".

Oracle's efforts to address these vulnerabilities resulted in a delay to the release of Java 8.[6]

2012

An OS X trojan referred to as Flashback exploited a vulnerability in Java, which had not been patched by Apple, although Oracle had already released a patch.[7] In April, Apple later released a removal tool for Lion users without Java.[8] With Java 7 Update 4, Oracle began to release Java directly for Lion and later.[9]

In October, Apple released an update that removed the Java plugin from all browsers.[10] This was seen as a move by Apple to distance OS X from Java.[11]

2013

In January, a zero-day vulnerability was found in all versions of Java 7, including the latest version Java 7 Update 10, which was already exploited in the wild.[12] The vulnerability was caused by a patch to fix an earlier vulnerability.[13] In response, Apple blacklisted the latest version of the Java plugin.[14] Oracle released a patch (Update 11) within three days.[15] Microsoft also released a patch for Internet Explorer versions 6, 7, and 8.[16]

Cyberespionage malware Red October was found exploiting a Java vulnerability that was patched in October 2011.[17] The website for Reporters Without Borders was also compromised by a Java vulnerability in versions prior to Update 11.[18]

After the release of Update 11, another vulnerability began circulating online,[19] which was later confirmed.[20] It was also found that Java's security mode itself was vulnerable due to a bug.[21] In response, Mozilla disabled Java (as well as Adobe Reader and Microsoft Silverlight) in Firefox by default,[22] while Apple blacklisted the latest Java plugin again.[23]

In February, Twitter reported that it had shut down an attack. Twitter advised users to disable Java, although it did not explain why.[24] Later in the month, Facebook reported that it had been hacked by a zero-day Java attack.[25] Apple also reported an attack.[26] It was found that a breach of an iPhone developer forum was used to attack Twitter, Facebook, and Apple.[27] The forum itself was unaware of the breach.[28] Following Twitter, Facebook, and Apple, Microsoft reported that it was also similarly compromised.[29]

Another vulnerability discovered allowed for the Java security sandbox to be completely bypassed in the original release of Java 7, as well as Updates 11 and 15.[30] In March, trojan called McRat was found exploiting a zero-day Java vulnerability.[31] Oracle then released another patch to address the vulnerability.[32]

Remove ads

See also

References

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads