You have a very strange threat model given how stunningly trivial it is to decompile .class files
I'm with you on the JNI but I am not willing to "baby with the bathwater" the Reflection API just avoid having to check the bytecode for Runtime.loadLibrary
I don't see how this is relevant. I'm talking at runtime. If I have a class:
class Point {
private final int x;
private final int y;
Point(int x, int y) {
if (x < 0) throw new IllegalArgumentException("x less than 0");
if (y < 0) throw new IllegalArgumentException("y less than 0");
this.x = x;
this.y = y;
}
}
You should not be able to use reflection to remove the private-ness of my field to set Y to -42, unless you are code within my module that I control.But as a general rule: as a library author I deeply resent people who cause ME to get blamed when I change an implementation detail and their fragile code breaks when my library gets upgraded.
> This update broke my workflow! My control key is hard to reach, so I hold spacebar instead, and I configured Emacs to interpret a rapid temperature rise as "control".
But security is just a small part of the problem. Remember all the breakages people had upgrading from 8 to 9+? Virtually all of them were do to libraries reaching into internals that then changed. If no internal method could change because someone might be relying on it then the platform can't evolve. If an application author cannot know which of her dependencies may be non-portable, they can't weigh the risk.
Yet another problem is optimisations. We can't optimise code if any dependency can freely decide to change the meaning of any line of code in the program.
private java.security.PrivateKey _key;
$ java -jar cfr.jar ...
$ sed -i"" -e s/private/public/g $(find . -name "*.java")
$ javac ...
and now Reflection doesn't need setAccessible and your threat model of "but my field is private!!11" has gone poofThe point I'm making is that I don't understand for the life of me whose problem this egregiously disruptive change is solving outside of the NSA, who I'm sure have their own JVM builds and can leave the rest of us out of it
Integrity is also a prerequisite to writing any security mechanism in any layer of the code that is less prone to accidental vulnerabilities in a third-level dependency, and it's also a prerequisite to performance optimisations. For example, if Java strings were immutable, the compiler would be able to optimise some operations on them. Except it can't because even thought they're almost always immutable, some third-level dependency may decide to mutate one string in the program, and because of that the compiler can't optimise any.
Such new and powerful functionality is indeed disruptive (in a good way), and all it demands is that libraries that need to, say, mutate Java strings or final fields let the application know so it could add a flag (if it's willing to take the portability/performance/security risks involved). That's it.
The semantics of encapsulation are sufficient. Anyone who breaks them knows it's on them, and if they don't, they certainly should have. It's not worth sweating all the maybes and what-ifs.
I agree, the issue arises when library developers make this decision and application developers have to deal with the fall out of that. Application developers need to know when things like this happen.
Second, the point about SecurityManager is a subtle one. SecurityManager was a complex security mechanism; this isn't. However, because integrity is a prerequisite to robust security, SM had to allow configuring integrity, but it was extremely hard to configure correctly. Now it's on by default.
If you have any sort of authentication/authorisation mechanism in your application (nothing to do with SecurityManager), then an accidental mistake in any dependency or transitive dependency may result in a vulnerability that would allow a remote attacker to bypass your security mechanism, because the attack surface area is the entire program.
Finally, the lack of integrity meant that some powerful performance optimisations can't be performed. Even simple constant-folding of Strings or final fields cannot be done because any library could unilaterally choose to mutate a String or a final.
That's as much an indictment of the Security Manager than anything else. ;-)
> Every one of these features were added because they were useful to java developers.
Which creates a requirement in my mind that removing those features needs to be justified by adding more benefit than they take out, but it is entirely possible that those features were the best way to address the needs of Java developers.
The reality is that Java is no longer seen has being a high integrity runtime anymore, so nobody uses it that way. The use cases for a high integrity runtime haven't gone away though.
I do see the "by default" in the title, but while I would be turbo sad I would also gladly accept -Djava.security.integrity=false to allow me to opt out of this DRM-esque stuff
And I say DRM but I could also imagine a world in which this stunt would be the death knell to Spring :-(
So, like I said: if you're a big HFT fund and you need your JVM to do crazy integrity assertions, good for you, but don't burn the whole world down for them. Hell, I would be Azul makes a killing catering to that audience, so let them sell an integrity enabled JVM and leave the rest of us out of this fight
> the big fat zero of times where someone has complained about an integrity violation on the JVM
~99% of the migration difficulties from 8 to 9+ were due to integrity violations of the core library (remember, module encapsulation was turned off by default until JDK 16). The cost of that alone is, well, high, and that doesn't even count library vulnerabilities. Integrity violations have been the #1 cause of complaints over the last several years.
Integrity is important because it is a prerequisite to portability ("upgradability"), security, correctness, and some important performance optimisations. If you haven't heard people complain a lot about any of these things then you haven't been listening.