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.