Clarification inline below

On 4/05/2021 8:35 am, Peter Firmstone wrote:
On 4/05/2021 5:12 am, Sean Mullan wrote:
-bcc jdk-dev
-cc security-dev

On 4/30/21 10:04 PM, Peter Firmstone wrote:
<SNIP>

In our software we use a ProtectionDomain to represent a remote server, because a thread only runs with the user's Subject (and that Subject must be carefully preserved for other threads), there is no way to represent the remote Server's Subject in a local domain , other than with a ProtectionDomain.   Our software is peer to peer, clients can be servers and servers can also be clients.  Code to interact with the server is downloaded via Maven and loaded.  Any permission's granted to a user, are injected into the stack when run as the client Subject, to authenticate the user for the server and establish a secure connection, calls made by the client are run with the user's Subject on the server, again for access control purposes.  This functionality is beyond the capability of Java RMI, we aren't using Java RMI to do this.  This is very important to allow us to make fine grained access control decisions, or perform event notification callbacks over secure connections, without this feature, we can't make a secure connection with a callback, and you know what happens when you have to do something, but cannot do it securely?   We only grant network access directly back to the server, downloaded code has been verified and is not expected to cause denial of service, by consuming resources etc, but we don't want to grant third party access to files, or random network connections, we still have privacy obligations for third party information.

We can allow a third party to use unsigned certificates to sign their jar files or use a checksum and we verify them using a secure connection to the server, prior to loading. We then dynamically grant permissions to the server's self signed Certificate (used to sign the jar file), or a ProtectionDomain, after authenticating the server and receiving a check sum or certificate from it.  So the client authenticates the server using signed TLS certificates (EG by letsencrypt.org or a trusted CA). We use self signed certificates on Jar files if we sign them, we are actually trusting the server entity in this case, eg a trusted company, but also placing restrictions on them.

I am probably missing something, but I don't understand how this is secure if you are using TLS server certificates as the basis for authenticating signed code. These are two very different use cases.


Clarifying the level of trust:

 1. You have a trusted party, whom you trust to write their own code.
 2. You run that code on your systems dynamically.
 3. You trust the other party, but you either haven't or it's not
    practical to audit their code.
 4. Using the principle of least privilege, you limit the ability of
    the other party's code to ensure they are unable observe data they
    shouldn't, eg a third party with whom you also do business.
 5. While a trusted party (eg a supplier) could write code that caused
    denial of service, eg using up all available memory, there is no
    motivation for them to do so.  However there may be motivation for
    them to see quotes on your system from another supplier if they
    have access to it.

The code is loaded dynamically, but before the jvm loads it, we authenticate the party that is asking us to load their code, after which we are basically asking them the question, is this the code you want us to load?  Please check that it hasn't been tampered with.   The trusted party gives us a checksum, or a self signed certificate they used to sign the jar, we are then satisfied that we have received the software unaltered from the trusted party and not a MITM attack, so we load it.   However we limit the permission of this software using the principle of least privilege.   They don't get file permissions, they are only allowed to connect to the server they used to authenticate with.  If a third party uses the same jar file, they don't gain the permissions granted to other parties, as it will be loaded into a separate ClassLoader with the permissions granted to that party only.

Just to clarify, these are software logic interactions.



If we remove access control, third parties will be able to open local network connections and freely and use Java Serialization over unsecured connections, exposing us to an attacker who can use a gadget attack. Presently they cannot open a network connection, access files or do much of anything without Permission.  All those protections will be removed with this JEP.

from https://community.letsencrypt.org/t/do-you-support-code-signing/370

Code-signing certificates as they’re used today are part of systems that try to decide whether a software source is malicious or legitimate. I don’t think Let’s Encrypt could easily play that kind of role when issuing certificates free of charge with an automated process without checking the real-world identity of the applicant. We could confirm that a code signing certificate applicant controls a domain name like iurewnrjewknkjqoiw.biz 408 <http://iurewnrjewknkjqoiw.biz>, but that doesn’t give users or operating system developers much ability to know whether software that that applicant publishes is trustworthy or malicious.

The JVM is one of very few platforms that has sufficient capability to allow us to do this.

If I could chose my pain, I would chose to remove Java Serialization first, before SecurityManager because while I understand the maintenance burden needs to be reduced for the ongoing viability of the Java platform, security is still of utmost importance, as the vulnerabilities of Java Serialization killed of client development.

I don't think it is appropriate to block deprecation of the Security Manager until serialization is removed. Note that we have added mechanisms such as Serialization Filters [1] to help applications secure their serialization dependencies and that do not require a Security Manager to be enabled. We also are continuing to look at other improvements in this area, as well as introducing new features such as Records that can be serialized more securely [2].

I'm not suggesting blocking deprecation of SecurityManager, I'm requesting blocking removal of SecurityManager until after Serialization has been removed.   So deprecate SecurityManager, just don't mark it for removal yet.  Please mark SecurityManager for removal after Serialization has been removed.   What follows is the reasoning for my request.

We currently use SecurityManager and policy to prevent un-trusted connections which could otherwise use serialization or access sensitive data.    We only allow a limited subset re-implementation of serialization over trusted connections and permission must be granted before it can be used.  No trust established (TLS), then no Serialization.  Because we load code dynamically, we will not be able to profile it in advance, so we cannot create serialization whitelists because we have no way of knowing class names in advance, our only choice will be to disable Serialization entirely.   At least with security policy, we can establish the permissions in advance.

Presently the dynamically loaded code, contains a list of requested Permissions in META-INF, however they may not be granted, the security policy has a list of Permission's that are allowed to be granted based on the remote principal, the permissions granted will be the intersection of these two lists, requested and allowed permissions.  We can log permissions that are not granted.  This occurs dynamically at runtime.  A Permission requested may also be a subset of the Permissions allowed, because of implies checks.  So dynamically loaded code really does operate under least privilege principles.  You can't do that with Serialization filtering.

Prior to the introduction of the Serialization's filtering mechanism, I re-implemented a subset of Java Serialization, focused on addressing vulnerabilities caused by gadget attacks.

We did this when other companies solutions to addressing Java vulnerabilities was to remove Java altogether, which is why Java applets are no longer used.  Instead, we knuckled down and addressed the vulnerabilities.

I had to remove circular links because they introduce security vulnerabilities, I also limited the number of bytes the stream can download before it must be reset, otherwise an IOException is thrown and control is returned to the caller.  It uses constructors, and all classes are expected to validate invariants.  We've discussed it previously.  Apart from Collection classes, serial form of existing classes has not been altered, instead classes have new Constructor's that are used to validate their de-serialized fields.  All fields have also undergone their own validation process.  J.B. called it atomic serialization, when we first discussed it, so that's what we call it.

My first step was to re-implement deserialization and use that for some time with the new deserialization public API,  I'm currently implementing a public API for serialization.  After this I will introduce more serialization protocols that use the same API, at that time I may have to change the serial form of some classes, as Java serialization had a lot of complex features that other serialization protocols lack.  The deserialization api, is capable of supporting multiple serial forms, to allow class implementations to change them.

Certain Java Collection classes are vulnerable to denial of service attacks, so they are not serialized, instead I have serializers that transfer the data, which is validated during deserialization, before populating the Java Collection classes via constructors.  This means any Collection class can be serialized, even those that don't implement Serializable, they all have the same serial form, so their serialized form basically respects the Collection interfaces of Map, Set and List, their bytes can be compared for equality, for example if two Map's are equal, their serialized bytes will also be equal.

Furthermore serialization filters have the same complexity flaws as the Security Manager model, but in our case we use SecurityManager to grant a limited set of privileges that we are able to establish prior to loading dynamic code.    We already have a profiling tool that generates policy files.

Once SecurityManager is removed, third party code will have all permission's granted to the JVM, so they will be able to view files and make network connections.   The serialization filters offer a similar level of complexity, but with less protection and less time for tool development.  No doubt this will require us to rethink the structure of our software and access control to sensitive data.

Once we fixed Policy performance issues and created profiling tools for initial creation of policy files, which are used as a guide to create the requested permission lists and enable permissions to be granted dynamically at runtime, security becomes a significant benefit rather than a burden.

To quote waratek: reference https://www.waratek.com/java-serialization-filtering/

To configure Serialization Filtering, the application needs to first be fully profiled. *Profiling* an app can be a complex process that requires specialized tools and has to be performed by domain experts. Typically, the process requires the app to run normally for a period of time in order for all its paths to be executed. A dynamic profiling tool can log the class names that are required for normal operation. This list of class names will then be the basis of configuring the white/black list of the Serialization Filters. And even after going through this process, there is no guarantee that all of the execution paths were run and all the required class names were logged. Of course, the same process needs to be performed every time a new release goes into production or even when a third-party library must be upgraded. The lifecycle of this process becomes even more complex since such any change in the Serialization Filters will first need to go through QA and UAT before it reaches production.

The Serialization Filtering mechanism follows a very similar approach to the Security Manager <https://docs.oracle.com/javase/7/docs/api/java/lang/SecurityManager.html>. The Security Manager also works based on a whitelist <https://docs.oracle.com/javase/tutorial/security/tour2/step3.html> and suffers from the same scalability problems. Java’s Security Manager has proved to be unsuitable for enterprise, large-scale environments, given that *it moves the responsibility of protecting the system to the user*. The user is responsible for understanding the application’s security requirements and technical details and correctly configuring the security policy, which in essence is a whitelist of permissions. Such security policies are typically very complicated in enterprise applications that change frequently and integrate with numerous different systems and components. The *operational cost* of correctly configuring and maintaining such security policies is so high that Security Manager is rarely deployed in production environments [6 <http://www.hpl.hp.com/techreports/98/HPL-98-79.pdf>] [7 <http://tomcat.apache.org/tomcat-7.0-doc/security-howto.html>].


I would elaborate that the above problems with SecurityManager have been address in practice, as we've had many years to address them, these solutions are not included with Java of course.  The responsibility is not with the user, but developers and administrators.

Also it has become apparent to me, that Java is following in the footsteps of Unix.   First workstations were replaced by cheaper PC's, so the workstation market was lost, then the PC version of Unix, Linux ate Unix's lunch in the Server market. Java no longer has a client market, no longer on phones or the browser, some desktop deployments, it has largely retreated to servers.  Be careful not to diminish Java's market too much, lest Android eat Java's server market lunch.  Android has a newer fine grained security model, I don't know if it can be applied to a server environment.   I don't mean to be inflammatory, just giving you ammunition, should you require it.

--
Regards,
Peter Firmstone
Zeus Project Services Pty Ltd.



--Sean

[1] https://docs.oracle.com/en/java/javase/16/core/serialization-filtering1.html#GUID-3ECB288D-E5BD-4412-892F-E9BB11D4C98A
[2] https://inside.java/2021/04/06/record-serialization-in-practise/

--
Regards,
Peter Firmstone
0498 286 363
Zeus Project Services Pty Ltd.

Reply via email to