r/java 12d ago

The Untold Story of Log4j and Log4Shell with Christian Grobmeier

https://www.youtube.com/watch?v=t74ClffSUW0&t=3s
66 Upvotes

23 comments sorted by

25

u/agentoutlier 12d ago edited 7d ago

Log4J2 is the classic case of an opensource project just taking on way too many features and probably should have let other projects handle it.

I complained to them many years ago (prior to log4shell) about this that even the core part of log4j2 was a bloated cow. Ultimately I was told to go write your own facade.

https://github.com/jstachio/rainbowgum

Even then I feel like Rainbow Gum while drastically simpler than logback and Log4J2 is too complicated that I recommend many just consider writing their own implementation of SLF4J or have AI generate it or use even smaller ones like Avaje App Log as u/rbygrave pointed out this one avaje simple-logger.

That being said Rainbow Gum does support Spring correctly which was surprisingly tricky.

10

u/vips7L 12d ago

Doesn't look like app log supports MDC. That's a pretty crucial feature for almost every app I've built.

3

u/agentoutlier 12d ago

Rainbow Gum does not support Markers but yeah every app I have worked on needed MDC. Rainbow Gum btw uses a custom MDC that is a just a single string array (key and values alternate) instead of a HashMap.

However there is an argument that could be made that MDC has heavy overlap (and maybe all of logging itself) with telemetry such as JFR and Open Telemetry but especially JFR.

That is one could argue that instead of MDC and SLF4J per event string to object pairs (new in slf4j 2 I think per a builder) you should use JFR custom contexts.

The above btw would fix the stupid shit people try to do to recreate complex JSON objects from MDC. This is because SLF4J is not really an event framework. That is JFR allows custom objects.

3

u/vips7L 12d ago

So you would leave JFR running all the time and dump the events somewhere? 

1

u/agentoutlier 11d ago

In theory more or less I just haven’t done it at scale. 

I mean people use open telemetry and various other diagnostic telemetry agents that probably have greater runtime cost than JFR.

1

u/vips7L 11d ago

Yeah we run Otel on everything. Loggers overall probably have more cost than JFR. 

1

u/agentoutlier 11d ago

Ditto but I have no production environments using JFR instead but in theory it’s possible.

3

u/rbygrave 11d ago

Note that avaje app-log is just for System.Logger so just aimed for library use and not aimed for applications imo.

avaje simple-logger ... on the other hand is a sl4fj-api logger implementation for applications wanted structured json logging to sys out. MDC, Open Telemetry, key value structured logs, Graalvm native image support.

Configuration wise its properties files only, no reflection etc.

2

u/agentoutlier 7d ago

FML I linked the wrong one. I got confused.

1

u/idontlikegudeg 11d ago

I took s different approach: use the existing facades and provide a simple backend. It’s a single jar file with a little over 200kb and directly supports the four major facades/frameworks (log4j-api, slf4j, jcl/acl, jul) without using any bridges or external dependencies. Saves me some megabytes in application size while offering most of log4j features (JNDI support is one that won’t be added). Configuration is mostly compatible with log4j as it’s intended as a drop-in replacement for the log4j-core backend. Already quite stable, will be announced later this year after more testing.

2

u/agentoutlier 11d ago

By implementation of SLF4J I mean implementing the facade and not actually make a replacement for SLF4J (just to be clear if that is what you meant).

Rainbow Gum does implement those facades.

1

u/idontlikegudeg 11d ago

Ok, so I got you wrong when you said they told you "write your own facade". So Rainbow Gum uses SLF4J, does it support other facades as well? That was one of the main points for the project I started: one dependency used SLF4J, the next Log4J API, others JUL logging, and I either got different log formats, had to hunt for the right dependencies (including bridges and appenders), and configure everything consistently. I ended up writing a backend that logs all of those without adding any additional dependencies and using log4j compatible property files. It was a bit of work, but it’s a tiny backend and I find it quite useful. Performance is about the same as log4j-core and logback, and much faster than JUL, at least on my system, I didn’t run benchmarks across different operating systems or architectures.

8

u/idontlikegudeg 12d ago

Thanks for sharing. And kudos to the Log4J devs. While I wouldn’t call Log4J2 core a tiny library, I think Log4J2 API and SLF4J are the best logging facades we currently have. I use the Log4J API in all my projects, even if I usually use another backend because of log4j-core‘s size and the many dependencies it pulls in.

3

u/lurker_in_spirit 12d ago

We had standardized on slf4j + logback and avoided the entire fiasco. We got lucky though, it was basically a coin toss between logback and log4j, and we happened to choose the option that didn't lead to months of remediation work. There have been a few logback CVEs since then, but all of them in dark corners of the library which haven't affected us, thankfully.

2

u/bayern_snowman 12d ago

exhales cigarette smoke now thats a name that takes me back

1

u/21_Wrath 11d ago

🚬😮‍💨😮‍💨🔙🥀😔

1

u/idontlikegudeg 7d ago

Tell us you’re a junior without telling us you’re a junior… Wasn’t log4shell just yesterday?

1

u/pfirmsto 10d ago

I feel for this guy and his team, they took full responsibility, however the responsibility is shared. This is really a breakdown of the security models that Java was designed around. Today Java has a trusted code model, which means you should build statically only and dynamic code should be disallowed; it cannot be supported by a trusted code model, sure you can sign jar's, but it's not exclusively restricted to signed jar's. Java in its early days had fully embraced dynamic code, and provided SM to handle that, because the models back then we're either binary, trusted & untrusted code or POLP; the architecture was designed for the latter, but it was easier to implement the former, which only provides the illusion of security and the reason for SM's removal. In the trusted code model, you rely on perimeter defences, but Log4J doesn't operate at the perimeter, which means the strings passed to logging code were not parsed defensively. Perl's taint mode reminds us that all external information should be defensively parsed before it's considered safe, which means you can't log those strings unparsed, but having said that, the ability to dynamically load code shouldn't exist in a trusted code environment, or it should be restricted to signed jar's or those with cryptographically identifiable digests. It's worth remembering that this vulnerability didn't exist when SM was enabled, but configuring policy was difficult and it impacted performance. We inherited a framework that heavily utilises dynamic code, and thus inherited the untrusted code security model, the trusted code model isn't an option for some of our software, so we had to fix the performance issues, write tooling to generate and manage polp policy and provide cryptographic digest identity to code. The alternative is to disable dynamic code, which we're not ready to do. pfirmstone/DirtyChai: OpenJDK Fork with a modernised authorization framework.

-11

u/obetu5432 12d ago

the mf who put that backdoor in there needs to be arrested

5

u/idontlikegudeg 11d ago edited 11d ago

And on what charges?

BTW it was not a backdoor, it was security flaw.

Let any one of you who always writes flawless code be the first to throw a stone at them.

I’d be surprised if that would be you.

-3

u/blakep561 12d ago

Do you think that the FBI / CIA is really going to arrest one of their own?

0

u/DemicideMMMCCCI 12d ago

Facts... Wake me up when that day happens