Java Security and the Java Ecosystem
Nicolas Frankel has worked with Java for decades and has seen a lot, especially on the dark sides of Java security. In this unscripted episode, he talks about his experience and how the Java ecosystem has changed over the years.
Preben Thorø: Thanks for joining us today. Nicolas Fränkel, I'm sure there is a more French way to pronounce that.
Nicolas Frankel: The problem is that it's a German last name. I'm born in France and many people pronounce it the English way, so even now I cannot tell you how it should be pronounced.
Preben Thorø: I know what you feel, my name is Preben Thorø. So please go ahead and be international with that. You have more than 20 years of Java experience. The last time I saw you live on the stage, you presented yourself as a security-minded developer, which I like very much, and I definitely consider you a Java expert with all the experience you have with the VM. One of the things you demonstrated in that presentation was how you can change the type of the class in Java. What is that about?
Nicolas Frankel: I learned, and probably most of you learned that Java is a strongly typed language, a statically typed language. So when you declare a variable, it's an Int, it's a class of whatever, it's a person, it's a double, it's whatever you want and then this type is written into the bytecode. Once the type is set, then you can use it. If you handle a person with attributes, first name, last name, and you've got an instance of type person you can query, "Hey, what is your first name? What is your last name?" And at the time, it was possible through introspection, through reflection, so through a Java API to change the type of a class at runtime.
I redid the talk recently because this is no longer possible in more recent JDKs. I think it's still possible up to 10, then in 11, you've got a warning, and I think it's 15, there is an exception, you cannot do it anymore. I can’t remember the exact details. So they fixed it finally, but at the time it was very funny that we say that Java is strong, statically typed. And then there’s Groovy. It is good but it's dynamically typed, you can do bad stuff where you can and you could do the same stuff in Java.
JVM - A hacker’s dream
Preben Thorø: So they fixed it, but I guess there are still a lot of legacy systems out there running the old Java versions. There was another thing that scared me even more. You showed on a running production system how you actually can change the bytecode to make it do whatever you feel it should do, but in a way, so if you restart the system, all traces would be gone.
Nicolas Frankel: Yeah. That's the hacker's dream for using it.
Preben Thorø: Isn't it?
Nicolas Frankel: Yes, you can actually do that. You need another JVM that will attach itself to the first one and inject bytecode into this first one and/or change the bytecode. You can do pretty bad stuff. You can also do pretty good stuff, but it is like everything, you have a lot of freedom on the JVM. The JVM provides you with so many possibilities that it's easy to misuse it. So on one side, you can use it to continuously deliver bytecode to your production system, meaning that your system never goes down. I have a talk about that. When there is a change on, let's say your computer, you can directly stream the bytecode to the production system with no downtime, it's just a prototype. But of course, if you are a hacker, you can use the same system to get money, like one penny on every transaction, or record the passwords.
Preben Thorø: Is that something that was possible with the old version but which has been fixed now?
Nicolas Frankel: So the changing of the type is now impossible, but the attach API is still possible. That's the problem of the JVM. You have a platform that allows you to do a lot of things, and in most cases, you only need to do a fraction of it. Most applications don't need to do that, but the JVM provides it anyway.
Preben Thorø: Should I be scared?
Everything is a back-door
Nicolas Frankel: You should. You have seen my talk. The conclusion of my talk was you can forget everything that I told you so far and life won't have changed for you, or you can start thinking that perhaps there is something missing in your setup and that problem is security. You have this huge platform and you need only a slice, so the rest is just an additional attack surface that hackers can use to wreak havoc on your system. I've shown the way to do it at the time and it was the security manager, which is also, of course, very old. It started with the applets. The idea at the time was that you had the JVM and you could run untrusted code on your computer from the internet. We should provide a sandbox, we should provide stuff that allows this untrusted code to work, and permissions to execute some stuff that we allow but not all because we don't want it to read our file system or to access our webcam. It was a permission system. The problem is that people still think that the security manager is about running untrusted code and untrusted code is just code that you download from the internet. The problem is untrusted code nowadays is every library that you are using.
Every dependency that you are using is basically untrusted code. The only way to trust this code is to audit it. And I believe that most companies don't audit the code they are using, they don't audit the dependencies. Did anybody ever audit Log4j for example? Log4j are simple, stupid libraries that everybody is using. I believe not. But even if you did, even if you audit the code, what makes you think that the source code that you audited is actually translated into the exact same binary that you are using? The only way to do that would be to not only audit the code but to build it yourself, then you can be sure that the binary does mirror the source code. I believe nobody has the resources or the willingness to do that. So we are trusting. Of course, sometimes there are certificates. But I don't know if a lot of companies are checking the certificates and you can tell that could never happen. It happened in the npm ecosystem.
Preben Thorø: Oh, yes.
Nicolas Frankel: There was a very well used library, which name I can’t recall right now. The maintainer said, “Hey folks, I have other stuff to do, who wants to maintain the library now?” And somebody stepped in. After a few versions, they realized that there was a back door into this library and they were mining cryptocurrencies. They were using your computer power to mine cryptocurrencies. Of course, you can say it can only happen in the npm ecosystem because it's just bad. Well, the Maven ecosystem is, in that case, just as bad, maybe Maven or Gradle or whatever, at least the repository, they are just repositories. You can publish it, you can publish your own stuff and anybody can use it.
I'm always using these as examples. Imagine you create a library that is really, really useful and people start using it, and at some point, you introduce additional capabilities. For example, steganography capabilities, ability to read bytecode in an image. So you would hide the bytecode in an image, or even source code in an image. Then when the image is read, you would be able to compile it on the fly and then execute the code and everything is possible. So this whole untrusted code myth is very strange that untrusted code is just applets. No. So some architectures rely on plugins, but even for dependency, for me is untrusted code.
Less is better
Preben Thorø: Yes, and in the Maven universe, does anyone know how many versions of comments logging you're actually including in your project?
Nicolas Frankel: That's a good question. I remember when I was still a consultant in one of the projects I was an architect and I started to check the WAR and all the libraries that were included in the WAR in this project. It took me half a day to cut the libraries in half because there were a lot of useless dependencies, redundancy, and dependencies in multiple versions. If you are really willing to do that, it's possible. But even if you restrict the number of libraries, which of course you should do, then again, how do you trust those libraries? With transitive dependencies in the JVM ecosystem which are much better than in npm where you are right-pad and left-pad, I think we are much more the same. That's still a lot of libraries for a simple application. A simple Spring application can have 30 dependencies, even 40 or 50. It's very easy. Some of them are small. Some of them are just configurations. Some of them actually contain bytecode.
I mentioned the fact that you would run it in a sandbox. This sandbox was defined by a policy file, and then you would enable the security manager on the JVM. This security manager by default would read this policy file and then you would only allow some of the capabilities that you're really, really willing to allow. Like if you have a web application, you probably want to open ports, which is good. You want to be able to listen to some ports, but why should you be able to access the whole file system? You should probably restrict the file system to the stuff that you really, really want to. The temporary folder is generally a good default because you do a lot of stuff, then you should disallow compilation, a lot of things like that.
Preben Thorø: This is about the VM. So it's not even a Java issue, is that correct?
Nicolas Frankel: No, it's a JVM.
Preben Thorø: It's all the languages like Kotlin, JRuby back in the times, Clojure, everything.
Nicolas Frankel: Yes, this security manager is congruent with the JVM. So you can run any language. Because in the end, you don't care about the language, you are running bytecode. And Kotlin bytecode can as much access the file system as Java bytecode. It's the same JVM API that you are using, or Clojure, or whatever.
Do your own security
Preben Thorø: So it's a very dark picture we are painting here of the VM. What can we do?
Nicolas Frankel: One way would have been to improve the security manager. Let's face it, creating a policy file is no walk in the park. You want to apply the least privilege principle so you should start from a blank policy file and add permissions. In my presentation, it was just a pet clinic and I think the policy file was 400 lines long. And this should be done when you create the application, when you update the libraries, when you remove libraries, when you add libraries, whenever you change the application. So this is really a huge downside, and I believe that's one of the reasons that I rarely saw the security manager used. But Oracle’s answer to that was, "Oh, it's so complicated. Let's remove it." And well, we don't care about that anymore. You should do your own security. Let's remove everything and do your own stuff. That's an interesting point of view.
Preben Thorø: It's an interesting approach, yes.
Nicolas Frankel: Yes. And we were a couple of people saying, "Hey, perhaps it's not that great." But how can I put it? Let's say that the team was not really interested in feedback. They are told, "Hey, it will be like this." And the only thing that we could achieve was that now in Java 17 it's deprecated, and there is a warning, but it still works. But there are systems relying on the security manager. Elasticsearch for example is relying on the security manager because they have a plug-in architecture. Well, they should be very afraid because there is nothing else to replace what they had.
Preben Thorø: I would like to leave a little light in the dark here.
Nicolas Frankel: Well, I'm French, so I'm not sure I'm the right person to ask. We are pretty gloomy and we are complaining all the time. The only alternative that I have is just on Java 17. Honestly, I believe most companies are at most at Java 11. So for them, it's not an issue. But for companies that are actually using the security manager, it's going to be an issue at some point, yes.
Preben Thorø: It sounds so. Okay. Thanks a lot. Thanks for joining us.
Nicolas Frankel: Sorry. No light at the end of the tunnel. I would wish to finish on a slightly more positive note, but actually, it's really hard for me to find anything good about this whole stuff. And it's not only about the security manager, it's about the approach that Oracle is taking regarding the feedback. It seems that they are not really community-oriented anymore if they ever were and I'm a bit afraid, honestly, about the future of if not the JVM at least Java.
Java has changed
Preben Thorø: I'd actually like to continue that one. I don't know if this will go into production, but back in the days, there used to be the JCP work which was very much community-driven. Does that still exist?
Nicolas Frankel: I'm not sure and I never was part of the JCP. A side effect I noticed is the Twitter account of Java retweeted a lot of stuff from the community before. My own articles sometimes got promoted by Java when I wrote about Java. But nowadays, nothing comes from the community anymore. It looks like they are only working with their developer advocates now. They are really good people. I mean, Nicolai, José, and David, I consider them good people, even friends, but it's really like on the rails and nothing should switch or go sideways. It's very, very centralized. And I feel it's really sad. I've two decades of experience. I'm learning Rust. I threw myself into Kotlin a couple of years ago. So I can say, I don't care about Java anymore. I can do my stuff, but for young junior developers, I'm not sure it's really a great idea. It's not a good signal.
Preben Thorø: It’s a problem that Java turned into a universe that it wasn't meant to be when it was first introduced many, many, many years ago.
Nicolas Frankel: I worked as a consultant for a long time, and I believe that Java was successful compared to Scala, for example, because it was very, very stable. You could run all your Java 1.0 applications on Java 1.5 or Java 8. For companies the most important thing is stability. You want stability at all costs because you don't want to rewrite your application every time you've got a new version, again, compared to Scala. And now Java has got a huge critical mass, and the strategy has changed a lot. Now they are deprecating things. At first, I was happy because some stuff that is deprecated is really like cruft. It is good to deprecate, but now they deprecate stuff that actually can be and is really useful and has no other alternative. Worse, the release cadence is crazy. I don't know any company that can match this release cadence. It's impossible.
Unless you are huge enough and you are IT-focused you can probably keep up with the cadence, but otherwise, you are doomed. I'm close to Switzerland, I think an administration I worked for just recently upgraded to Java 8, for God's sake. Of course, the administration is not known for being moving forwards really very fast, but I believe they are more representative of the whole industry than companies that can keep up the pace with the six-month cadence. So they are releasing very, very fast and deprecating faster and faster. I believe that it's going to be a bigger problem with each release that it will fragment the ecosystem.
I mean, we already saw it with the module system. I think it was two years ago that I did an analysis. I took 20 of the most used libraries and checked whether they were compatible with the module system. Not modules themselves, but just auto modules, meaning you just needed to add an additional line into your META-INF MANIFEST.MF. One line, that doesn't change anything. Half of them were not compatible. So if you want to use modules in your application your libraries need to be at least compatible. If they're not compatible, I wrote an article about it, it's a mess. So we saw this great divide, companies being afraid to move beyond Java 8 because of the modules, and now it's getting faster and faster.
Again, I'm French, I'm complaining all the time. I'm also pessimistic, but I believe that in that case, it's not a great move. I understand that for some people, the most tech-oriented one, it's good to have a faster release cadence, but before it was every four or five years. Now, it's every six months. Perhaps there is a good middle ground. I think we switched to the other extreme here and it's going to be hard. But let's see, perhaps I'm completely wrong.
Preben Thorø: Back in the days, we had Java 2 standard edition. I guess the other one never even existed. We had J2SE for like applications, and then we had the EE edition, J2EE if you wanted to go big scale. The idea was that everything was in a controlled environment, that the server would set up everything for you. So that leads me back to the question: Does Java become something now that it wasn't intended to be back then? Is that the problem?
Nicolas Frankel: I cannot answer that question because when I started using Java, it was 1.3 for a couple of months, then it was 1.4. So at the time, I didn't think a lot about what was the point of Java or whatever, I was just happy to learn the API. The good thing is during those two decades, I've read a lot of blog posts about Java is dead. And of course, I found them always very funny because Java is definitely not dead. But this current speed of release might be like an impediment for Java adoption or at least it will definitely fragment the ecosystem. So I know that starting from Java 9, you can have JAR that is multi-released, that you can have dedicated classes for each Java version, it just shifts the burden to the library maintainers. So again, I'm not super optimistic for the future.
Preben Thorø: That was a wonderful way to end this conversation. Thank you.
Nicolas Frankel: Now I will receive a lot of hate mail from all Java developers from Oracle, but that's fine.
Preben Thorø: I really encourage everybody to go and check the talk on this link here.
Nicolas Frankel: Actually it's a bit outdated, yeah, but it was the time it was recorded.
Preben Thorø: It might be outdated but so are all the Java installations out there.
Nicolas Frankel: No worries. It was just to tell you.
Preben Thorø: Thanks a lot. Thanks for joining us.
Nicolas Frankel: Thanks a lot.
Nicolas Frankel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with narrower interests like Software Quality, Build Processes and Rich Internet Applications. Currently working for Hazelcast. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.