On 21/06/2023 8:52 pm, Ron Pressler wrote:
On 21 Jun 2023, at 01:36, Peter Firmstone<peter.firmst...@zeus.net.au> wrote:
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.
Maintaining that information is the very thing that makes the mechanism so
expensive. Annotations wouldn’t make it any easier, because their placement
would still have to be tested and maintained. No one is preventing you from
maintaining that information yourself, and you are free to inject such
annotations into the JDK to your heart’s content. If it really isn't too much
work then we all win — we don’t have to do it and test it, and you still get to
have it.
I wish it was that simple, it's an auditors nightmare.
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.
That is clearly untrue because even the most security sensitive applications
already prefer alternatives that they find superior. We’re not sending people
over to other alternatives; people first abandoned SM in favour of alternatives
and *then* we figured it’s time to remove SM when few were left using it. I
believe ElasticSearch are now relying on strong encapsulation to maintain their
Java-level security invariants.
I would suggest looking into it a little further before dismissing it
out of hand or making assumptions.
This discussion on OpenSearch is worth a read.
https://github.com/opensearch-project/OpenSearch/issues/1687
My question is still/why/? That's why I asked@davidlago
<https://github.com/davidlago>of what actual CVEs JSM mitigated.
There's some effort to "move security into core", with that,@rmuir
<https://github.com/rmuir>@uschindler
<https://github.com/uschindler>what is your argument for not
removing JSM?
Because currently I don't see replacements for a lot of the
functionality. Meanwhile the protection still works so why discard the
only security mechanism that you have? I think I explained above, but
to summarize for specific vulnerabilities that are of concern (e.g.
have happened before), in a world without a security manager, I think
the easiest win is to harden the systemd service, Currently it is very
weak and
insecure:https://github.com/opensearch-project/OpenSearch/blob/main/distribution/packages/src/common/systemd/opensearch.service
These are some of the historically problematic issues that the
security manager prevents... aka the worst-of-the-worst:
* RCE: there's some protection by seccomp etc via systemcallfilter
which disables fork/exec at OS level. So even without security
manager, there is at least basic protection from allowing someone
to execute coin miner or whatever. This piece has to remain as you
can't block fork/exec with systemd seccomp filters... But I'd
still recommend to start hardening the systemd service
with|SystemCallFilter=|to take it further (the seccomp bpf rules
will "nest" just fine).
* File/Directory traversal et al: currently the security manager is
the only thing restricting the filesystem. opensearch does not
need to be able to access files in users home directories or
anything like that. If there is a bug in the code that would allow
this, instead of accessing users private files, security manager
will deliver a SecurityException. but, alternatively, the
directories that can be read and written can be nicely restricted
with systemd service as well (stuff like|ReadWritePaths=|)
I recommend looking at a secure systemd service as an example, and
comparing it to the current one, here is a good
one:https://github.com/archlinux/svntogit-community/blob/packages/dnscrypt-proxy/trunk/dnscrypt-proxy.service
You may also use|systemd-analyze security opensearch.service|to track
your progress, it will suggest improvements.
<SNIP>
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.
Okay, but we, .NET (the other platform that had a similar mechanism), and most
security experts have lost faith in the approach and gained faith in newish
OS-level protections that weren’t available when SM was introduced (and also
offer protection for native code as well as better protection from some DOS
attacks); no new security sensitive platform seems to take that stack-based
approach, either. This means that even if we’re wrong on the technical merits,
such a feature is so far from the mainstream practice that it has no room in a
mainstream language. If some day it becomes mainstream again things may change.
Still, here’s one thing about the technical aspect: “Trusted” does not mean “free of
vulnerabilities” but "assumed to not be malicious.” Libraries can and do have
vulnerabilities, but I think that strong encapsulation is much more effective in
controlling their blast radius, and it has significant non-security-related
benefits, too (not that most developers are rushing to apply strong encapsulation to
their own code, but at least we’re able to encapsulate the JDK itself). By
“effective” I don’t mean “powerful”, but rather “provides more value on average when
all aspects are considered”. With strong encapsulation you only need to check that a
particular code unit that performs an operation on behalf of a user (authorised at
the application operation level) doesn’t do anything problematic. Other units cannot
break your unit’s invariants, so only local reasoning is required (true, the size of
the unit is not as small as could be afforded by a stack-based approach, but it is
still local and contained). If you’re interested in gadget attacks, I suggest you
think about how many of them can be prevented by strong encapsulation alone and how
many could be prevented by a combination of strong encapsulation and OS-level
protections that apply to the entire process (you can throw in serialization
filters, too). In other words, don’t think just about what SM could do for you, but
also think about what the more popular approaches do for you, too (taking your own
advice of considering how they can be best applied, not misapplied) and then
consider how much effort should be put to close the *delta* between the two.
I agree with you regarding the benefits of encapsulation.
Prior to serial filters, we reimplemented Java deserialization, we used
a standardised constructor signature, and we removed the ability to
serialize graphs with circular references, we placed data limits on
streams, cumulative limits on array sizes and required a periodical
reset, we basically applied strong encapsulation with atomic failure and
input validation to serialization to eliminate gadget attacks.
We've got a mature implementation for managing authentication and
authorization in a dynamic distributed environment. It's not a simple
problem to solve, so the complexity likely comes from the problem
domain, rather than the solution. I've been using it many years, and
over those years, the problems have all been solved one by one, to the
point where it's a well understood stable solution for our problem domain.
But the reality is, there are no other existing solutions, so we are
unable to migrate, we need an actual concrete implementation, promising
future developments are great, but we need a clear migration path, today
no such alternative technology exists. As you pointed out .NET has
removed their equivalent, so we can't migrate to .NET either. Like all
problems, someone will come up with a better solution at some point,
when they do, we'll migrate to that, until then, we have to continue
using what we have. OpenJDK doesn't know the answer, and they don't want
the burden of the existing solution, that's fair enough. We need to be
honest with our users, we don't have a future migration path with Java
at this time.
Perhaps it will be solved like concurrency was with functional
programming, another language will solve it elegantly, hey maybe Java
will copy the functionality :)
Anyway, we know where we stand now and that's better than thinking we
had a migration option when we didn't.
- Peter.
Code signing is a completely separate topic; expect some developments in that
area.
— Ron