[External] : Re: PrivilegedAction et al and JEP411

Peter Firmstone peter.firmstone at zeus.net.au
Wed Jun 21 00:36:03 UTC 2023


On 20/06/2023 9:04 pm, Ron Pressler wrote:
>
>> On 20 Jun 2023, at 06:26, Peter Firmstone<peter.firmstone at zeus.net.au>  wrote:
>>
>> Don't get me wrong, it's good that OpenJDK is improving encapsulation, it's just OpenJDK is also undoing years of tested and hardened API's,
> You probably meant that as a bad thing, but I read it as thank you for serving your users!

No, not at all, you're welcome.   I recognise there are different levels 
of trust, for different applications, you're bringing some of the 
benefits a well deployed SM provides, without the deployment cost to 
people who aren't using it now and in doing so improving their 
security.   Although we don't agree on everything, there are things we 
agree on, and just because we disagree on some things doesn't mean I 
don't respect your opinions.   I realise that SM will be removed, I'm 
just disappointed that we are being prevented from reimplementing a 
replacement authorization layer in Java, without any compromise from 
OpenJDK it's not possible.  We at least need to retain some kind of 
privilege action mechanism. That doesn't even have to be a privileged 
action, maybe it could be an annotation, that we can find using StackWalker.

Authorization isn't a one size fits all, it's for high value assets, 
usually determined by risk assessment, Java was once promoted as a 
secure language for enterprise.

If data protected isn't of high value, or is of low complexity, a 
solution of appropriate cost will be applied, in many cases that isn't 
SM, however removing SM will reduce security below an acceptable level 
for a percentage of developers and software projects, the number may be 
small, but the impact will be widespread, just look at how widely 
deployed ElasticSearch and OpenSearch are.   JGDMS only gets about 30 
unique cloners per fortnight, and about 50 clones, but sometimes its up 
around 200, I don't know how widely used it is.   But we aren't the only 
projects using it for where there is no replacement possible. There are 
many parts of the Java API, which aren't used by all developers.   So 
far, even though I still use some of the other API's which have been 
removed from OpenJDK, it's been pretty straightforward to replace them 
with something else.  SM (JAAS Authorization) isn't replaceable.

I've been using and SM for 20 years, it's a lot simpler than people 
realise, there is a way to use it, that makes it easy, and there are 
ways not to, that are guaranteed to cause pain.

Arguments against SM, that I've read on this list are based on bad 
practises, or the lack of tooling provided with the default 
implementation, this indicates a lack of experience in use, I know that 
Alan and Sean were involved during the early days with Li Gong, but I'm 
pretty sure they don't have much experience deploying it, feel free to 
prove me wrong if my assumption is incorrect.   I'd suggest cost of 
maintenance also appears overestimated, this is partly due to policy, I 
have offered to assist with maintenance, however my offer was rejected, 
as this is considered part of security, I am not permitted to assist, I 
could submit patches to this list, but I'm not sure they'll be welcomed 
or accepted.

When SM is used incorrectly, complexity is significantly increased, 
however the API's could be simplified, which would improve security and 
reduce complexity and maintenance.

SM no more impacts developers who don't use it, than developers who 
don't use XML.   The biggest maintenance burden I see on OpenJDK is Java 
Serialization.

One dedicated full time resource should be sufficient, to review code 
changes to check for compliance.  It's not difficult for me to track 
down where permissions are leaking from Java API's, however I've assumed 
that as it's deprecated, there will be little interest in fixing them, 
is my assumption incorrect?   I think this looks like a big task, 
because there is a lack of tooling. SpotBugs also provides static 
analysis to find these problems, although now that SM is deprecated, 
users are requesting it to be removed from SpotBugs.

Even an imperfect authorization layer is far better than no 
authorization layer at all.

Lets discuss how it should be used, and what benefits it provides and 
the situations when you might want to use it.    I only ask that people 
keep an open mind and for the moment, forget all the horror stories.  I 
realise this is academic now, and unlikely to change anything, however 
documenting it here might serve some historical purpose.

Firstly, if used correctly, using authorization is no more difficult 
than using an Executor framework.

Some ground rules:

 1. Users create data.  The level of trust you have for the user
    determines the level of trust you have for their data.
 2. Developers create code.   The level of trust you have for the
    developers determines the level of trust you have for their code.
 3. Always, always, use automated tooling for the creation and
    management of policy files, start with an empty policy file with no
    permissions.
 4. Apply the principle of least privilege.
 5. Developers, users and administrators will make mistakes, no one is
    perfect, mistakes can be fixed once identified, try to find ways to
    identify mistakes, for example, check generated policy files for
    leaking privileges, this indicates that a developer has forgotten to
    use a PrivilegedAction.
 6. Attempts at sandboxing have always failed historically, with
    increasing language complexity, the more likely a sandbox will be
    broken through, never run untrusted code, avoid parsing data from
    unauthenticated sources.  For example, code can perform DOS and use
    up all the memory on your system to bring it down. Pictures can
    contain code, which can be compiled and run, data can contain SQL
    injection attacks.   Always validate input, eg use pattern matching
    to sanitize text.
 7. Some architectures are more secure than others, for example, OpenBSD
    on Sparc or ARM is not susceptible to Spectre, Meltdown or similar
    attacks.
 8. SM is not a sandbox, it is an authorization layer only.

There are different levels of trust, for different users and different 
developers.   Note that historically, Sun or the JRE had unlimited trust 
for its own developers, this was a mistake.   100% Trusted code should 
be minimised to bootstrap code.

Trust is from 0% to 100%.  0% is an unauthenticated user 
(unauthenticated unknown data source), while 100% is your administrator, 
there are many levels of trust in between. Applied to developers, 0% is 
the unknown software your user downloaded from the internet, 100% 
shouldn't be given to developers, only bootstrap code.  I don't trust 
myself 100% either.

General guidance:

 1.   If you are not authenticating users, using data integrity
    checksums, or encryption, then you are unlikely to benefit from SM. 
    SM only provides authorization, you cannot make authorization
    decisions without first authenticating, you have to establish trust
    exists, before you can determine an appropriate level of trust.
 2. Privileges must be granted to both users and developers, for
    software to function, using tooling to determine permissions required.
 3. There is no such thing as 100% trusted developers, all developers
    make mistakes.   Java Serialization is my case in point, it bypassed
    all protections and there was no DataPermission("deserialize") to
    allow authorization decisions to be made based on the authenticated
    user who supplied the data, in many cases, due to the 100% trust
    given to Java de-serialization code, there were no adequate defences.
 4. When the developer is given 100% trust (AllPermission, or a JRE
    ProtectionDomain with a null codesource), then the user will also be
    trusted 100%, when this code parses the user data, this is why so
    many gadget attacks were successful.
 5. If 100% trust is given to developers, it adds unnecessary
    programming complexity to reduce that trust for users, that's seldom
    applied in practise.
 6. As the developer, if you are writing code that parses data, you must
    add permission checks before parsing, this allows the prevention of
    parsing data from an untrusted user.
 7. As the developer, if you are opening a network socket, accessing the
    file system, key stores or properties, do so using a
    PrivilegedAction.  Keep the privileged action short and sweet, eg if
    opening a socket, only do what's necessary to open the socket, and
    return it.
 8. PrivilegedAction's can be used with AccessController, and
    AccessControlContext, to elevate, preserve or reduce privilege,
    however it is most commonly used to elevate it.
 9. Don't use the Policy provider supplied with OpenJDK, it relies on
    DNS.   Performance and scaling is horrible, with many synchronized
    locks, network and file system access, sorry I don't intend to
    offend, it was written a long time ago, it's basically broken.
10. Generate your policy files using a deployment environment, by
    working the software through all of its use cases, for each role.  
    Properties should be defined, so the policy file generation tool can
    replace file paths and network addresses in policy files with
    configurable properties.   The policy writing tool only appends
    missing permissions, this is to allow policy files to be built up
    incrementally, periodically, the entire policy file should be
    regenerated, for example, following a software update.
11. Permissions in policy files will determine the users who can access
    properties, files, network, or developers who use agents.
12. All external connections should require authentication.   All
    authenticated connections should be given a thread of execution with
    the Subject of the authenticated user.
13. All code should either be signed, or be given a SHA256 hash or better.
14. Permissions can be used to control many Java features, such as the
    attach api, reflection, code downloads, network connections, but has
    no power to control Java serialization for example.

Example of a policy grant made by the policy writing tool, notice how 
both the code and principal are required to have these permissions, that 
means the user cannot accidentally grant these privileges to untrusted 
code, and it means the code doesn't have permission if the user isn't 
authenticated, or has the wrong credentials, the tooling works this out 
for you, following the rules of the principle of least privilege, you 
don't have to figure it out yourself, tooling significantly reduces 
complexity and provides for embarrassment free, well organised deployment:

grant codebase "file:/${qa.home}/lib/jinitests.jar",
     principal javax.security.auth.x500.X500Principal "CN=Tester"
{
     permission net.jini.security.GrantPermission 
"java.lang.reflect.ReflectPermission 
\"newProxyInPackage.org.apache.river.mahalo\", \"\"; 
org.apache.river.api.io.DeSerializationPermission \"ATOMIC\"; 
java.lang.RuntimePermission \"accessClassInPackage.com.sun.proxy\", 
\"\"; org.apache.river.api.io.DeSerializationPermission \"ATOMIC\"; 
java.lang.RuntimePermission \"accessClassInPackage.com.sun.proxy\", \"\";";
     permission net.jini.security.GrantPermission 
"net.jini.security.AuthenticationPermission 
\"javax.security.auth.x500.X500Principal \\\"CN=Tester\\\" peer 
javax.security.auth.x500.X500Principal \\\"CN=Mahalo\\\"\", \"connect\";";
     permission java.net.URLPermission 
"http://${HOST}:9080/mahalo-dl-3.1.1-SNAPSHOT.jar", "GET:";
     permission net.jini.security.AuthenticationPermission 
"javax.security.auth.x500.X500Principal \"CN=Tester\" peer 
javax.security.auth.x500.X500Principal \"CN=Mahalo\"", "accept";
     permission java.io.FilePermission 
"${jsk.home}${/}lib-dl${/}${mahalo-dl.jar}", "read";
     permission java.io.FilePermission 
"${jsk.home}${/}lib${/}${mahalo.jar}", "read";
     permission java.io.FilePermission 
"${qa.home}${/}harness${/}configs${/}jsse${/}mahalo${/}mahalo.config", 
"read";
     permission java.io.FilePermission 
"${qa.home}${/}harness${/}policy${/}defaultsecuremahalo.policy", "read";
     permission java.io.FilePermission 
"${qa.home}${/}harness${/}trust${/}mahalo.keystore", "read";
     permission java.io.FilePermission 
"${qa.home}${/}lib${/}qa1-mahalo-dl.jar", "read";
};

If we remove the ability of the Java platform to manage different levels 
of trust, by removing authorization, then all trust becomes 100%, for 
users who authenticate and developers whose code you run, you grant them 
100% trust, to access anything that might be available from within the 
JVM.   So now you have to set file permissions and firewall permissions 
to prevent the application from doing unauthorized things.

I would also go as far to say that no permissions is the right approach 
for loom, one perform a privileged action in a Thread, maybe using a 
task in a thread pool, then hand it off to loom, the same goes for 
ForkJoin thread pools.


> Our duty is to maximise the utility of the JDK. The reality of the economics of software — in this case, the finite resources available to us — demands that we work on features with a relatively high ratio of utility to cost and that we do not work on features with a relatively low ratio of utility to cost. And by “utility” I mean economic utility, i.e. the total value to the ecosystem. If someone invented a galactic teleporter that no one uses, even for silly reasons — say, they don’t like its colour — its economic utility is zero.
>
> Let me put it bluntly and only somewhat inaccurately: Every feature added to Java over the past few years is one that we believe will serve at least a million Java developers (directly or indirectly); in fact, most features added to Java have had a million users in other languages before even being considered for addition to Java based on their technical merits (of course, the calculus changes depending on cost).
>
>
>> that we're expected to come up with DIY solutions for, with zero care from OpenJDK and some very bad examples of alternative solutions,
> The alternative solutions are the ones preferred by the vast majority of users who, I would assume, think they are superior solutions. We are simply unable to also provide a separate solution, let alone such an expensive one, for a very small minority. It would be unfair to most of our users.
>
>> not to mention a completely wrong assessment of SM based on an outdated poorly maintained implementation, with lack of use and maintenance burden (when the community is willing but not allowed to maintain it) as justification for it's removal.
>
> The community has not shown any willingness to maintain SM. As with other features, we only ever keep something to be maintained by others if they show both the commitment and the requisite ability (e.g. the JDK ports and GCs that are not maintained by Oracle). There are other companies beside Oracle that regularly contribute substantial, excellent work to OpenJDK, but to date none of them do so at the scale required for this, and we’re talking companies that pay several developers to work full time on OpenJDK. And that’s not even the worst of it. One of the things that makes SM so costly is that it’s not a separable feature but a cross-cutting concern that every JDK developer working primarily in the core-libraries area needs to worry about it when working on many changes in many areas.
>
> I don’t think you’ve begun to appreciate the enormity of this task, but even you complained that injecting doPrivileged calls in keeping up with all the changes to the JDK is too much work and that’s before studying the test suite that tests all of these places.
>
>> SecurityManager is just an authorization layer (that allows assigning different levels of trust), not a magic wand designed to solve all security problems (or sandbox, it was only a component in the sandbox, along with bytecode verification and ClassLoader visibility), to be discarded because it doesn't solve some other unrelated security flaw, it's an Non Functional Requirement, it doesn't bring in any revenue for Oracle, nor does it for many other development projects, so management have knocked it on the head, we get it.
> You don’t get it, because it wasn't management. The technical leadership decided to remove SM on the advice of our security experts because they’ve judged that it’s harming our users by demanding too much effort for something that too few people want to use. If management gave us fifty more developers tomorrow to employ as we please, we still wouldn’t be able to maintain SM because our responsibility to our users would still demand that we use those resources for things that would give our users more utility.


The message I got, was it was a maintenance expense OpenJDK doesn't 
want, that indicates a commercial decision.   I have seen arguments 
against it documented on JEP411, but these only apply to the 
implementation of the Policy provider supplied with OpenJDK and lack of 
tooling for policy file creation.   These arguments are in error, and 
I've demonstrated that previously, with fully functional high 
performance high scaling code.

The problem is not that SecurityManager is being removed, the problem is 
we have come to depend on using Authorization in Java, and now we are 
being prevented from reimplementing anything to replace it.

We can handle the stack walk, using the attach api to insert guards, but 
without privileged calls in OpenJDK, permissions cannot be applied using 
the principle of least privilege, it will be broken and not useful.   
Basically all authorization support foundations are being removed along 
with SecurityManager, there's nothing we can do to fix it.   Java's no 
longer a platform that supports authorization.

SM was just the implementation, maybe it wasn't right, and maybe the 
experts are right to remove it.  But maybe they're wrong too.


>
> Even the most security-conscious of our users have shown a clear preference for other solutions. Your argument is that you know better than the market, but one of the world’s most popular mainstream languages cannot be led in this way. Perhaps you believe that better marketing would make the market see the light, but we have a hard enough time educating our users about features that a million others already enjoy in other languages, and an even harder time educating them about more unique features (such as strong encapsulation) that in a few short years have already paid more dividends than SM. Imagine how hard it would be to convince them of an approach that’s been abandoned after a couple of decades by the users of *both* popular platforms that adopted it.
>
>> We know that Oracle intends to remove authorization from the Java platform, we also know that there is nothing we can say to convince Oracle it's a bad idea, the only thing management will understand is bad consequences, such as bad news headlines.   I understand that Oracle needs to monetize Java
> If you mean that a small group of users is unable to convince us to do what they wish at the expense of most of our users, then you’re right. You say “monetize Java”, but what that really means is that you understand — without acknowledging — that most people don’t find your solution to be superior and don’t want it. I fully sympathise with the frustration when the wider public doesn’t share our views as I frequently experience it myself, but you seem to blaming us for acting rationally and accepting the reality of the market we serve.
>
>> the only thing management will understand is bad consequences, such as bad news headlines.
> I think what they’ll understand is actual demand. Get some real traction then we can talk again.
>
>> We've been working hard at implementing authorization for many years, to protect against attacks, but suddenly the threat is gone?   Yeah right, there's a bridge in Brooklyn for sale.
> That is untrue, and you speak as if it’s 1996, not 2023. The threat is not gone, but the vast majority of those writing secure servers prefer other solutions to address such threats, in particular those provided at the OS level. That approach has pros and cons and we could argue on the intellectual merits of both approaches all day, but no one can deny that the economic utility of the popular approach is much higher than the one you like. Maybe you’re right and you know better than everyone else, but in that case it’s not us that you need to convince; you need to convince the market.


Most of the market has low risk, low consequences for security breaches, 
that's why security is often an afterthought, or non functional 
requirement.   It's the low probability, high consequence outcomes that 
need protection, and these are a much smaller part of the market.   
Still it will be damaging to Java's reputation when one of the high 
consequence outcomes is realised.   There's going to be a lot of legacy 
code that isn't taking advantage of module encapsulation, something will 
go bang at some point.


>
> BTW, we’re not removing authorisation from the Java platform. Most Java applications have authorisation and virtually none of them use SM. What you mean is removing independent checks from low level operations inside the JDK.

Yes, JEP 411 is removing JAAS authorization from the Java platform.  
Here's a refresher if you need it: 
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/tutorials/AcnAndAzn.html


>
>> The decision has been made, it's final, the debate is over, we're just waiting for the removal notice now.   How about someone raise a JEP to remove security manager, targeting a particular release version (preferably 22, but so be it if it's 21) so we can remove uncertainty and notify our users of the versions of Java we'll be supporting going forward?   Then it's over and we can stop worrying about it.
> We will (try to) follow the same process we follow for all changes, including more impactful ones. We don’t yet know what changes will be in JDK 22, let alone later releases. When we do, so will everyone else. I hope we’ll find ways to improve our process in the future so that it will inconvenience you less.

What will help will be a predictable roadmap, so we can do some planning 
around that.

Thank you for your time, we both know SM is being removed, lets not 
waste any more of each others time discussing it, we just need to know 
which versions of Java we'll be unable to support and a timeline around 
that.   Then that opens the door to assessing which language platform is 
best suited to our needs going forward.

Thank you, respectfully,

Peter.

>
> — Ron
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20230621/d65910fd/attachment.htm>


More information about the security-dev mailing list