The new code was written by a different department, so I'm a little hazy on the details, but I doubt it. It's a 25 years old line of business app, and it's in violation of every guideline, rule and law it touches, and only alive because it got grandfathered through various certifications and audits.
99% of the work was redesigning the business process it supports to be in compliance, and then write a new LOB app that takes inspiration from the old one, but works with the new process.
You might be able to use AI for the remaining 1% mind- and pointless boilerplate code Java requires for no good reason.
Trust me, you don't want that job :D I've been fighting to get our services to Java 21 from Java 8/11 for the last year or so, I've been partially successful but our main API (and 1/2 monolith) is still a dropwizard app on Java 11
No, it's a long deprecated JVM that is effectively abandoned. But it's still a good minimum target as all of its successors tend to be backwards compatible. But you'd typically use one of the more recent LTS versions.
Of course there are quite a few crypto libraries out there, including several JWT related ones. A challenge in that space is that there have of course been some platform changes over the years. Not all of the newer algorithms are supported in older JDKs. And some of the alternatives are a bit complicated in terms of dependencies. I've had some issues with some of Google's libraries dragging in everything and the kitchen sink in terms of dependencies and then causing conflicts with my other dependencies when one of those dependencies changes their API.
This one looks like it builds on bouncycastle and not much else. Which explains how it is not really that dependent on what comes with the JDK as bouncy castle provides its own implementations for a lot of the popular crypto stuff.
Often it is significantly cheaper to pay for a longer term supported release of an older Java version than it is to upgrade your application to use a later release. So yeah, kinda?
Indeed and I wish more people really understood this.
I don't really like to target JDK8 as a supported version at work. However, I have to because of large, complex dependencies (some third-party with no source available) that have no drop-in replacements that will work under JDK9 and beyond.
Finding replacements for dependencies (or rewriting them), testing, etc to move to newer versions of Java is a cost the business is not willing to absorb at this point. I expect that eventually when JDK8 has no viable support options and the cost of maintenance becomes too great the business will decide to jettison the whole stack and replace it with something else that likely won't be Java based.
Migrating anything at least somehow complicated past Java 8 is PITA. When you are at Java 9, you are half done. Full done if you don't use some libraries that abuse JVM (like lombok). For most of those it would be enough to upgrade to newest versions.
Java 8 -> 11 upgrade was kind of a pain, and so was 11 -> 17. After that though, it's smooth sailing. I think breaking changes for the module system are over.
I would argue differently, it is better to use latest JDK, it always has best support and fixes.
Most maintained libraries keep their code compatible with it, if one doesn't then I would be cautious in using it as it is a big red light, that notifies given maintainer doesn't have enough time, so any fixes might not get there in time (or ever). Think of it like a litmus test.
LTS makes sense if you are paying for it and updating your JDK as soon as there is a release of LTS JDK (so AFAIR usually once every 1-2 months. Which is exactly what you would do with the current JDK.
Because you won't have to schedule full compatibility testing of your
app in order to find out that there were breaking changes in the newest
JDK version that require the user to fix the app. You can just not
update the major version of JRE for a long time. The JRE will still be
updated with security fixes and bugs, but no breaking changes should be
introduced.
Developers can focus on extending functionality instead of maintenance
and porting the app to new JRE. Devops can focus on different things
than adapting the environment to the new requirements that were broken
in new JRE major version. Product managers don't need to create another
spreadsheet columns to mark compatibility issues.
The problem with "most libraries keeping their code compatible with the
newest JRE version" is that most projects use a library that is not
kept up-to-date with the newest JRE version. Often that library is the
library which has no alternatives. Also switching libraries is rarely a
trivial thing to do.
Using bleeding edge software also means that we participate in "beta" testing. Company-oriented human resource management would suggest that the resources the company spends should be about the needs of the company, not some thirdparty product.
Newer JDK usually means new features that makes programmers life easier -> less maintenance in the long run. This is not construction work, this is programming, new means better.
If one doesn't have automated regression testing then that is a red light.
You can do beta testing, with EA, not with GA.
Oracle broke compatibility between Java 8 and Java 9+, so many of the libraries that have a dependency on older functionality are not getting maintained. Java 8 is turning into a dangerous space because even though the JDK is getting patched quarterly, much of the components that work with it are not. It is only going to get worse. SpringBoot, for example, requires either a commercial contract for Java 8/11 support or Java 17+ for the community supported stuff.
> Oracle broke compatibility between Java 8 and Java 9+,
No it didn't. Introduction of modules (Java Platform Module System (JPMS)) would be mostly transparent to majority of users.
> so many of the libraries that have a dependency on older functionality are not getting maintained.
Any example? (I already herad the same argument on bluesky and asked for example and suprisingly didn't get it either)
The biggest issue around that time was switching from javax to jakarta namespace but that's somewhat on the side of the Java versioning.
> Java 8 is turning into a dangerous space because even though the JDK is getting patched quarterly, much of the components that work with it are not.
Again - examples?
If the library is not update then it could happen in any ecosystem - python, c# and whatnot.
> It is only going to get worse. SpringBoot, for example, requires either a commercial contract for Java 8/11 support or Java 17+ for the community supported stuff.
Of for f sake - if you are still stuck on Java 8 (released a decated ago) and didn't update then it's only your fault. Supporting ancient platform cost money so you either put that money to be up to date or you pay companies to maintain compatibility you ancient stock. MS is doing the same with old OSs and virtually any other company requires to pay/pay more to support old stuff... (because it costs money)
I'm coming in as someone who helped get thousands of Java 8 based SpringBoot 2.x apps to Java 17/21 and SpringBoot 3.x, so a non-trivial portion of my last year. The javax -> jakarta namespace was a part of the issue. Turns out, we had a lot of things using jaxb as either a direct or transient dependency. About 10% of the apps were some form of old school Java EE which faced the same issue. None of the porting is hard once you've sat down and done it once - but we had team after team who were doing it the first time. We also got to find out who was using deprecated packages, as release by release from 9+, they started to be deleted. Way too many libs were using Sun's base64 encoder.
The point here is that Java is getting updated and the core JDK is just fine. We are seeing components drop support for Java 1-8, requiring 9+. And yes, that could happen in any ecosystem. It is happening in Java ecosystem today. If you crawl GitHub and look at what is vibrant and what is becoming abandoned, you will see the unmaintained legacy stuff stuck on Java 8. CVEs are a terrible way to say security risk - but it does show trends.
Since about 80% of our Java apps are SpringBoot based, when SpringBoot 2.7.18 being the last 2.x community release that reached EOL in November of last year. That version released with Spring Framework 5.3.31 - Spring Framework is currently 5.3.41 or so for those getting commercial patching. This is the last version that supported Java 8 through 11. Similar issue with MapR. This traps people on specific Java versions, which then traps them to an aging ecosystem of components.
The parent asked - why not target Java 8? That is why. If the parent asked, should I be compatible with Java 21-8, I'd say fine. It is a company's fault if they found themselves on an EOL product. Please, for the love of god... don't enable teams to remain there by making ANYTHING that requires Java 8.
None of this is hard until you have so many that it is.
While javax->jakarta was huge PITA (less motivated by technialities but more by politics though) let me introduce you to https://docs.openrewrite.org/ which should make such upgrades easier :)
I made a tool in Java recently where I was expecting relatively untechnical people to wind up using. Decided to check if there was a version of Java already on a Windows 10 tablet I've had but not really used and it had 8 on it so I developed to version to minimise the need to guide people through installing a newer version.
I hadn't used Java since my first year of programming and didn't want to spend too long on it. As it was basically a game modding tool I just wanted a jar that works on a wide variety of devices because that's what I'm used to in that scene as a user.
I didn't even know Jlink was a thing though, thanks for mentioning it! will look into it to see if it's worth adding whenever I return to the project
Not really, we run multiple prod apps on Java 8. Sure, there is migration in the pipeline, but that's about it, its solid as rock and that's all business cares about.
We run a ton of legacy cruft that's still on Java 8. Extended support is available until at least 2030. It's rock solid for us and migration is not easy unfortunately, even Java 11 is a challenge.
Java 23 is non LTS. We use java 21 (the most recent LTS) for our internal stack, but for maximum compatibility we support java 8 for this library (and our other open source libraries, including our java client library/SDK).
Why? It's a library so the more platform it supports the better. There is nothing inherently wrong with that and if the author wants to put up with the lack of modern features and syntactic sugar then why not?
I'm pretty sad to see all these JWT libraries which go out of their way to implement RSA-based algorithms (don't we all love massively-sized tokens? with ancient and hard-to-secure algorithms), why they almost universally fail to implement the most decent option JOSE offers for asymmetric signatures: Ed25519 [1].
Why would you trust that the RSA implementation baked into Java (or anything for that matter), is safe? Java is also implemented by human beings.
The Java RSA implementation apparently had a timing side-channel attack vulnerability for many years that was only discovered this year[1].
I don't know if there were more serious issues with the Java RSA implementation, in the past, but the same cannot be said about their ECDSA implementation. It was completely broken for a while before it was discovered[2].
Bad implementation can happen with any algorithm, but if the algorithm is simpler and built to be more foolproof like Ed25519, that's just far less likely. Unfortunately most of these libraries are not written by a professional cryptographer who codes without bugs, and even Daniel J. Bernstein, a cryptography expert who IS famous for writing software without almost no bugs[3], criticized RSA and ECDSA[4] and designed Ed25519.
To be honest, if even djb doesn't want to implement RSA and ECDSA then I honestly think nobody should.
Yes, and you've just demonstrated the problem here. People believe RSA is secure if you just use 2048 bit keys, but the problem with RSA is the key themselves... And the padding scheme.
For starters, let's look at the keys. You need to select a safe public exponent and safe private parameters. If you generate the key with openssl without mucking around with the parameters, you're likely to get a pretty strong key, but nobody guarantees the key is safely generated.
To constant, in Ed25519 (or Curve25519) your key is just a random 256-bit string (32 bytes) with a a couple of bits being ignored. All keys are secure and you cannot generate or use an insecure key.
Cryptosystem Rule #1: A good cryptosystem does not let yet generate insecure keys.
Then you've got side-channel attacks. RSA is far more vulnerable to timing and cache side-channel attacks, due to its complex BigInteger math that usually relies on code that was designed for solving math problems, not for cryptographic operations. The Big Integer math also makes implementing RSA harder, and therefore RSA implementations are more likely to have bugs.
Ed25519 is a good counterexample yet again. djb has famously implemented it in just a few 280-character tweets in TweetNacl[1]. The entire library contains Ed25519, Curve25519, Salsa20, Poly1305, SHA-512 and HMAC in 100 tweets or 800 lines of C code.
Yes, there are many toy RSA implementations out there that are even shorter than that, but they either only use regular integers (limiting your RSA keys to puny 64 bits at best) or using third-party non-cryptographic Big Integer Math libraries, which brings us back to square one.
Cryptosystem Rule #2: A good cryptosystem is designed to avoid cache and timing attacks.
Cryptosystem Rule #3: A good cryptosystem is designed to be simple to implement
The last issue is the padding. Almost all RSA implementations out there use PKCS#1 v1.5 padding, which has been known to be insecure for decades now. It is vulnerable to a padding oracle attack known as Bleichenbacher's Attack [2]. It's easier to exploit PKCS#1 v1.5 with RSA encryption than with RSA signatures, but it can also be exploited with signatures[3].
Ed25519 does not need any kind of padding. The signed data is always pre-hashed with the same hash which is defined by the algorithm (SHA-512).
Cryptosystem Rule #4: If possible at all, do not require padding (e.g. use pre-hashed signaturesand stream cipher construction).
If you don't trust me on this, you should still follow Latacora's Cryptographic Right Answers:
Ed25519, the NaCl/libsodium default, is by far the most popular public key signature scheme outside of Bitcoin.
It’s misuse-resistant and carefully designed in other ways as well.
You shouldn’t freelance this either; get it from NaCl.
Avoid: RSA-PKCS1v15, RSA, ECDSA, DSA; really, especially avoid conventional DSA and ECDSA.
52 comments
[ 4.1 ms ] story [ 101 ms ] threadI doubt we'll get around to the Java 8 stuff before 2030.
99% of the work was redesigning the business process it supports to be in compliance, and then write a new LOB app that takes inspiration from the old one, but works with the new process.
You might be able to use AI for the remaining 1% mind- and pointless boilerplate code Java requires for no good reason.
Of course there are quite a few crypto libraries out there, including several JWT related ones. A challenge in that space is that there have of course been some platform changes over the years. Not all of the newer algorithms are supported in older JDKs. And some of the alternatives are a bit complicated in terms of dependencies. I've had some issues with some of Google's libraries dragging in everything and the kitchen sink in terms of dependencies and then causing conflicts with my other dependencies when one of those dependencies changes their API.
This one looks like it builds on bouncycastle and not much else. Which explains how it is not really that dependent on what comes with the JDK as bouncy castle provides its own implementations for a lot of the popular crypto stuff.
https://github.com/FusionAuth/fusionauth-jwt/blob/main/src/m...
I don't really like to target JDK8 as a supported version at work. However, I have to because of large, complex dependencies (some third-party with no source available) that have no drop-in replacements that will work under JDK9 and beyond.
Finding replacements for dependencies (or rewriting them), testing, etc to move to newer versions of Java is a cost the business is not willing to absorb at this point. I expect that eventually when JDK8 has no viable support options and the cost of maintenance becomes too great the business will decide to jettison the whole stack and replace it with something else that likely won't be Java based.
If version 8 is still a relevant target, there's a problem.
actually you're doing worse than throwaway work: you're creating more work (one more thing to migrate to newer java in 2026).
BTW. Next year we will have Java 25.
Current LTS is Java 21, it's supported until 2028 -- a much longer timeline than Java 24.
I would argue differently, it is better to use latest JDK, it always has best support and fixes.
Most maintained libraries keep their code compatible with it, if one doesn't then I would be cautious in using it as it is a big red light, that notifies given maintainer doesn't have enough time, so any fixes might not get there in time (or ever). Think of it like a litmus test.
LTS makes sense if you are paying for it and updating your JDK as soon as there is a release of LTS JDK (so AFAIR usually once every 1-2 months. Which is exactly what you would do with the current JDK.
Developers can focus on extending functionality instead of maintenance and porting the app to new JRE. Devops can focus on different things than adapting the environment to the new requirements that were broken in new JRE major version. Product managers don't need to create another spreadsheet columns to mark compatibility issues.
The problem with "most libraries keeping their code compatible with the newest JRE version" is that most projects use a library that is not kept up-to-date with the newest JRE version. Often that library is the library which has no alternatives. Also switching libraries is rarely a trivial thing to do.
Using bleeding edge software also means that we participate in "beta" testing. Company-oriented human resource management would suggest that the resources the company spends should be about the needs of the company, not some thirdparty product.
If one doesn't have automated regression testing then that is a red light. You can do beta testing, with EA, not with GA.
> Oracle broke compatibility between Java 8 and Java 9+,
No it didn't. Introduction of modules (Java Platform Module System (JPMS)) would be mostly transparent to majority of users.
> so many of the libraries that have a dependency on older functionality are not getting maintained.
Any example? (I already herad the same argument on bluesky and asked for example and suprisingly didn't get it either)
The biggest issue around that time was switching from javax to jakarta namespace but that's somewhat on the side of the Java versioning.
> Java 8 is turning into a dangerous space because even though the JDK is getting patched quarterly, much of the components that work with it are not.
Again - examples?
If the library is not update then it could happen in any ecosystem - python, c# and whatnot.
> It is only going to get worse. SpringBoot, for example, requires either a commercial contract for Java 8/11 support or Java 17+ for the community supported stuff.
Of for f sake - if you are still stuck on Java 8 (released a decated ago) and didn't update then it's only your fault. Supporting ancient platform cost money so you either put that money to be up to date or you pay companies to maintain compatibility you ancient stock. MS is doing the same with old OSs and virtually any other company requires to pay/pay more to support old stuff... (because it costs money)
The point here is that Java is getting updated and the core JDK is just fine. We are seeing components drop support for Java 1-8, requiring 9+. And yes, that could happen in any ecosystem. It is happening in Java ecosystem today. If you crawl GitHub and look at what is vibrant and what is becoming abandoned, you will see the unmaintained legacy stuff stuck on Java 8. CVEs are a terrible way to say security risk - but it does show trends.
Since about 80% of our Java apps are SpringBoot based, when SpringBoot 2.7.18 being the last 2.x community release that reached EOL in November of last year. That version released with Spring Framework 5.3.31 - Spring Framework is currently 5.3.41 or so for those getting commercial patching. This is the last version that supported Java 8 through 11. Similar issue with MapR. This traps people on specific Java versions, which then traps them to an aging ecosystem of components.
The parent asked - why not target Java 8? That is why. If the parent asked, should I be compatible with Java 21-8, I'd say fine. It is a company's fault if they found themselves on an EOL product. Please, for the love of god... don't enable teams to remain there by making ANYTHING that requires Java 8.
None of this is hard until you have so many that it is.
I didn't even know Jlink was a thing though, thanks for mentioning it! will look into it to see if it's worth adding whenever I return to the project
According to this java survey: https://www.azul.com/wp-content/uploads/final-2023-state-of-... , 40% of organizations use java 8.
When that number gets much much lower, it'll be worth talking about not supporting java 8.
[1] https://datatracker.ietf.org/doc/html/rfc8032
The Java RSA implementation apparently had a timing side-channel attack vulnerability for many years that was only discovered this year[1].
I don't know if there were more serious issues with the Java RSA implementation, in the past, but the same cannot be said about their ECDSA implementation. It was completely broken for a while before it was discovered[2].
Bad implementation can happen with any algorithm, but if the algorithm is simpler and built to be more foolproof like Ed25519, that's just far less likely. Unfortunately most of these libraries are not written by a professional cryptographer who codes without bugs, and even Daniel J. Bernstein, a cryptography expert who IS famous for writing software without almost no bugs[3], criticized RSA and ECDSA[4] and designed Ed25519.
To be honest, if even djb doesn't want to implement RSA and ECDSA then I honestly think nobody should.
---
[1] https://www.rapid7.com/db/vulnerabilities/redhat_linux-cve-2...
[2] https://www.cryptomathic.com/blog/explaining-the-java-ecdsa-...
[3] http://www.aaronsw.com/weblog/djb
[4] https://blog.cr.yp.to/20140323-ecdsa.html
For starters, let's look at the keys. You need to select a safe public exponent and safe private parameters. If you generate the key with openssl without mucking around with the parameters, you're likely to get a pretty strong key, but nobody guarantees the key is safely generated.
To constant, in Ed25519 (or Curve25519) your key is just a random 256-bit string (32 bytes) with a a couple of bits being ignored. All keys are secure and you cannot generate or use an insecure key.
Cryptosystem Rule #1: A good cryptosystem does not let yet generate insecure keys.
Then you've got side-channel attacks. RSA is far more vulnerable to timing and cache side-channel attacks, due to its complex BigInteger math that usually relies on code that was designed for solving math problems, not for cryptographic operations. The Big Integer math also makes implementing RSA harder, and therefore RSA implementations are more likely to have bugs.
Ed25519 is a good counterexample yet again. djb has famously implemented it in just a few 280-character tweets in TweetNacl[1]. The entire library contains Ed25519, Curve25519, Salsa20, Poly1305, SHA-512 and HMAC in 100 tweets or 800 lines of C code.
Yes, there are many toy RSA implementations out there that are even shorter than that, but they either only use regular integers (limiting your RSA keys to puny 64 bits at best) or using third-party non-cryptographic Big Integer Math libraries, which brings us back to square one.
Cryptosystem Rule #2: A good cryptosystem is designed to avoid cache and timing attacks.
Cryptosystem Rule #3: A good cryptosystem is designed to be simple to implement
The last issue is the padding. Almost all RSA implementations out there use PKCS#1 v1.5 padding, which has been known to be insecure for decades now. It is vulnerable to a padding oracle attack known as Bleichenbacher's Attack [2]. It's easier to exploit PKCS#1 v1.5 with RSA encryption than with RSA signatures, but it can also be exploited with signatures[3].
Ed25519 does not need any kind of padding. The signed data is always pre-hashed with the same hash which is defined by the algorithm (SHA-512).
Cryptosystem Rule #4: If possible at all, do not require padding (e.g. use pre-hashed signaturesand stream cipher construction).
If you don't trust me on this, you should still follow Latacora's Cryptographic Right Answers:
You can look at this blog for more information:https://blog.trailofbits.com/2019/07/08/fuck-rsa/
---
[1] https://tweetnacl.cr.yp.to/
[2] https://en.wikipedia.org/wiki/Padding_oracle_attack#Asymmetr...
[3] https://mailarchive.ietf.org/arch/msg/openpgp/5rnE9ZRN1AokBV...
RSA is by far the most common algo needed for integrations, so I can't imagine not supporting it.
We have an open issue about supporting EDDSA (of which Ed25519 is the most likely implementation) https://github.com/FusionAuth/fusionauth-jwt/issues/13 but it hasn't gotten shipped due to other priorities.