> Perl/Python/Ruby/PHP and friends all have eval()...
PS: eval() is also very bad per se, and IMHO it's a dangerous feature when used outside of a REPL or a debug environment. The fact that others already have bad features or are doing dubious things doesn't give you a free pass for doing them yourself. It never does, it's like saying that committing a crime is OK as long as everyone else does the same.
This whole thing exists because Java has basically kept around a way of pulling off something akin to
wget -O - someurl | sh
but with extra steps for more than 20 years. This is absolutely insane even from a '90s perspective, the whole idea is broken and it absolutely bewilders me that `com.sun.jndi.ldap.object.trustURLCodebase` was only set to false by default in 2018. This is utter rubbish; support for arbitrary URL codebases should have been canned decades ago, not 3 years ago.The fact that JNDI can pull random code from a server like that is absolutely nonsensical trash, no matter how one spins it.
Still, in Python you can GET and eval:
r = urllib.request.urlopen(url).read()
d = literal_eval(r.decode())
Here's someone "Fetching and evaluating Python code from an HTTP response":https://stackoverflow.com/questions/28047761/fetching-and-ev...
Edit: Apparently `literal_eval` isn't so dangerous -- but one could replace it with `eval()`. /Edit
But you didn't start writing "absolutely insane" about Python ... Or maybe Python too is insane? And there should be a separate Python executable, with eval included?
What if Python shipped 2 executables?
python # there's no eval()
python-with-eval # danger! now you can use eval()
(And Java as well: `java` couldn't load any code dynamically, but `java-danger-dyn-code` could?)By the way, you can do the same thing everywhere, nothing stops you from doing
system("sh -c \"wget -O - someurl | gcc -x c - && ./a.out\"")
in C and allow the world to pwn you. What is arguable here is that in this case it is definitely not the language or the system's fault if their users are so dumb to invent a creative way to abuse a facility intended for a different use.Viceversa, the JRE includes and standardizes facilities to potentially download and execute code without any reasonable sandboxing by default, out of the box, in the standard install. It's as if Python had mandated by standard to check if the data passed to `eval()` is an HTTP URL in order to download and eval() whatever resides at that address. It's not the same by any margin. One thing is to shoot yourself in the foot by mistake , one other is to have in your toolbox a device that by design chops your feet off. The thing that bewilders me is that the whole "let's download untrusted .class files from the Internet" thing was a deliberate design choice and it took people 25 years to realize how idiotic it was. There's a whole sea of difference between that and what you've described.
r = urllib.request.urlopen(url).read()
d = literal_eval(r.decode())
But rather: r = urllib.request.urlopen(url).read()
logging.info(r.content)
Wouldn't that be pretty insane if the those two code fragments were functionally equivalent?Force the user to restart everything if they need a plugin?
Or do you want to force developers to only ever write monolithic software now?
Yes. Hopefully ensures that only people authorized to actually restart the service can add arbitrary code.
In fairness, Java has had capabilities to only let signed code run since its early days (it was fundamental for stuff like Applets or RMI), but like the rest of Java the whole specification is over engineered and quite complicate so nobody bothers with it. There are just too many old features lying around in the JRE that should be off by default. Like they shouldn't be possible to use unless you explicitly configure your environment to enable them. 99.999% of apps do not need and will never care about JNDI, and having it just lying around doing nothing just pointlessly increases the surface attack of your application for no good reason.
Because Java supports naked sockets [1], so that is what you would have to do to block the network traffic from containing .class files.
(Or remove the capability of real networking. I suppose we can agree that a language which doesn't support networking is quite limited in its use nowadays?)
[1] https://docs.oracle.com/en/java/javase/16/docs/api/java.base...
1. You can write a raw socket, pull a class file, put it in the right place, and load it using classloaders (assuming they don't want to abolish dynamic class-loading)
and
2. The language has a conventional way of loading arbitrary classes over the network using the standard library.
Any turing complete language can download and execute code. Even if the language doesn't support it natively, you can write an interpreter that acts on some code/bytecode. However, some languages support hot-loading code over the network in a straightforward way, while others force you to do all the work yourself (with attendant limitations). In effect, those languages require you to take the gun, check that it is loaded, and very carefully point it at your own foot.