JEP 411: Deprecate the Security Manager for Removal

OwnerSean Mullan
TypeFeature
ScopeSE
StatusCandidate
Componentsecurity-libs / java.security
Discussionsecurity dash dev at openjdk dot java dot net
EffortM
DurationM
Reviewed byAlan Bateman, Alex Buckley, Brian Goetz
Created2021/04/05 14:19
Updated2021/05/13 14:39
Issue8264713

Summary

Deprecate the Security Manager for removal in a future release. The Security Manager dates from Java 1.0. It has not been the primary means of securing client-side Java code for many years, and it has rarely been used to secure server-side code. To move Java forward, we intend to deprecate the Security Manager for removal in concert with the legacy Applet API (JEP 398).

Goals

Non-Goals

It is not a goal to provide a replacement for the Security Manager. Future JEPs or enhancements may define new APIs or mechanisms for specific use cases, depending upon demand.

Motivation

The Java Platform emphasizes security. The integrity of data is protected by the Java language and VM's built-in memory safety: Variables are initialized before use, array bounds are checked, and memory deallocation is completely automatic. Meanwhile, the confidentiality of data is protected by the Java class libraries' trusted implementations of modern cryptographic algorithms and protocols such as SHA-3, EdDSA, and TLS 1.3. Security is a dynamic science, thus we continuously update the Java Platform to address new vulnerabilities and to reflect new industry postures, for example by deprecating weak cryptographic protocols.

One long-time element of security is the Security Manager, which dates from Java 1.0. In the era of Java applets downloaded by web browsers, the Security Manager protected the integrity of users' machines and the confidentiality of their data by running applets in a sandbox, which denied access to resources such as the file system or the network. The small size of the Java class libraries — only eight java.* packages in Java 1.0 — made it feasible for code in, e.g., java.io to consult with the Security Manager before performing any operation. The Security Manager drew a bright line between untrusted code (applets from a remote machine) and trusted code (classes on the local machine): It would approve all operations involving resource access for trusted code but reject them for untrusted code.

As interest in Java grew, we introduced signed applets to allow the Security Manager to place trust in remote code, thereby allowing applets to access the same resources as local code run via java on the command line. Simultaneously, the Java class libraries were expanding rapidly — Java 1.1 introduced JavaBeans, JDBC, Reflection, RMI, and Serialization — which meant that trusted code gained access to significant new resources such as database connections, RMI servers, and reflective objects. Allowing all trusted code to access all resources was undesirable, so in Java 1.2 we redesigned the Security Manager to focus on applying the principle of least privilege: All code would be treated as untrusted by default, subject to sandbox-style controls that prevented access to resources, and users would place trust in specific codebases by granting them specific permissions to access specific resources. In theory, an application JAR on the classpath might be more limited in how it uses the JDK than an applet from the Internet.

The Security Manager, then, had ambitions to protect against two kinds of threat: Malicious intent, especially in remote code, and accidental vulnerabilities, where limiting permissions would serve as a defense-in-depth mechanism to mitigate the scope of vulnerabilities, especially in local code.

Most permissions are about preventing malicious intent, but the threat of remote code has receded: The Applet API was deprecated in Java 9 in 2017, the closed-source browser plugin that ran applets was removed from Oracle's JDK 11 in 2018 along with the closed-source Java Web Start technology, and running untrusted code of remote origin is no longer industry practice.

Most of the risks that the Security Manager protects against are no longer significant, and the Security Manager does not protect against risks that are significant. Even if users grant permissions cautiously, the Security Manager cannot address 19 of the 25 most dangerous issues identified by industry leaders in 2020, and cannot protect against speculative execution vulnerabilities.

This lack of efficacy against malicious intent is unfortunate because the Security Manager is, of necessity, woven into the fabric of the Java class libraries. As such, it is an ongoing maintenance burden. All new features and APIs must be evaluated to ensure that they behave correctly when the Security Manager is enabled. Access control based on the least-privilege principle may have been feasible in the class libraries of Java 1.0, but the rapid growth of java.* and javax.* packages led to dozens of permissions and hundreds of permission checks throughout the JDK. This is a significant surface area to keep secure, especially since permissions can interact in surprising ways. Some permissions, e.g., allow application or library code to perform a series of safe operations whose overall effect is sufficiently unsafe that it would require a more powerful permission if granted directly.

As to providing defense-in-depth against vulnerabilities, the Security Manager is rarely the answer for a variety of reasons.

There is no significant interest in developing modern Java applications with the Security Manager. Making access-control decisions based on permissions is unwieldy, slow, and falling out of favor across the industry; .NET, e.g., no longer supports it. Security is better achieved by providing integrity at lower levels of the Java Platform — by, for example, strengthening module boundaries (JEP 403) to prevent access to JDK implementation details, and hardening the implementation itself — and by isolating the entire Java runtime from sensitive resources via out-of-process mechanisms such as containers and hypervisors. To move the Java Platform forward, we will deprecate the legacy Security Manager technology for removal from the JDK.

Description

We propose four actions:

Deprecate APIs for removal

The scope of the Security Manager is broad, covering many APIs in addition to java.lang.SecurityManager. We will thus deprecate a number of APIs, all of which are related to the Security Manager. We will not, however, deprecate APIs that have value independent of the Security Manager, or whose removal presents a high compatibility risk.

We will terminally deprecate eleven classes and seven methods (denoted by :: syntax) by annotating them with @Deprecated(forRemoval=true):

We will not deprecate some classes in the java.security package that are related to the Security Manager, for varying reasons:

We will not deprecate any tools. (We removed the policytool GUI for editing policy files in JDK 10.)

Issue warnings

We propose to make the following changes to the JDK to notify developers and users that the Security Manager is deprecated for removal:

Alternate JAAS APIs

JAAS provides APIs that authenticate and authorize users. The Subject::doAs APIs extend the Security Manager's code-based access-control model to also take into account the user, or Subject, that is running the code. Different mechanisms such as GSSAPI and Kerberos can use the credentials in a Subject for authorization decisions. The Java Platform, by default, obtains credentials from the private or public credential sets associated with the Subject in the current thread's access-control context via the Subject::getSubject(AccessControlContext) API.

A typical flow using JAAS, GSSAPI, and Kerberos is as follows: An application calls Subject::doAs with two parameters, namely a Subject containing credentials previously obtained via a JAAS login, and a PrivilegedAction or PrivilegedExceptionAction that executes a GSSAPI operation such as GSSManager::createCredential(), GSSContext::acceptSecContext(), or GSSContext::initSecContext(). An underlying Kerberos provider then accesses the Subject by calling Subject::getSubject(AccessControlContext) and retrieves or populates Kerberos credentials related to the subject. The application then uses these credentials for subsequent GSSAPI operations.

In effect, Subject::doAs is used as a mechanism to transport credentials across API boundaries by attaching them to the thread's AccessControlContext, serving a purpose similar to a ThreadLocal. These credentials can be used for purposes other than code-based access control without enabling the Security Manager. However, they depend on APIs tightly related to the Security Manager, such as AccessController and DomainCombiner.

We should continue to support this important use case. Decoupling this behavior from the Security Manager APIs and defining new APIs may be the best way forward. We will add further details to this section as work progresses.

Alternatives

Testing

Risks and Assumptions