Log4jmemes.com: for those of us that need a laugh
log4jmemes.com
log4jmemes.com
I've always done this, never have I used a library for this, because:
- running manually? >myapp.log 2>&1
- using systemd? use journalctl
- using docker/kubernetes? capture automatically the stdout/stderr of your containers and pipe them through logstash or something
Real question: why would an application need to know where its logs go? This is not in the business perimeter, but the ops perimeter. Am I wrong?EDIT:
Most responses are about configuring logging level, output format, etc... This can be done with a print-based approach without sending a request to an external service (which would need to trust you and your inputs).
Example: Python's default logging module.
Still, thank you for your insightful answers :)
Also legacy; before systemd/docker/kubernetes, applications had to send to syslog themselves.
You are not a real Java Programmer then.
Imagine being able to enjoy the Java syntax without feeling the need to write everything with a minimum of three levels of abstraction!
Break free of the tyranny of getters and setters! Make that integer public!
No more oppression from type introspection! Hang Spring and Hibernate from the gallows!
The Java revolution starts TODAY!
Text, though, is a pretty universal interface and I would rather wrap a binary and stream it’s output than integrate a logging library natively.
I did work with a product once that had local logs in a ring buffer and only shipped “important” logs to centralised storage, and that was nice but required context which can’t be easily gleaned from the content of a message.
$ ./myapp &>myapp.log
# Get error messages mentioning "foobar"
$ jq -c 'select(.severity=="error")' | grep "foobar" | jq -r '.message'> This is not in the business perimeter, but the ops perimeter.
That is a great point. Logging configuration should be provided at runtime, not compiled into the application. That's why most places provide the logging configuration as a runtime parameter.
log4j allows libraries to implement logging and allow the end user to worry about where the logs go, at the application level, usually via config on the command line (e.g. modifying classpaths).
In the Java world before cloud-native we had application servers like Tomcat and JBoss which typically used something like log4j (log4j-core package) to configure what gets logged and where the logs should be shipped to. These application servers where shared and usually hosted more than 1 application. Hence the need to do contextual lookups (jndi and others) to determine log routing or enrich log messages with contextual information.
Applications or libraries running inside these application servers would only implement a logging api (log4j-api package) which is just a facade so every application can write implementation-independant logging and let the application server provide the implementation and configuration.
Now in the cloud-native/12-factor world, the industry has moved away from application servers (or embeds an app-specific server in the container) so it makes sense to just log to stdout and let the container orchestration handle log shipping and filtering. The former role of log4j is now mostly handled by Fluentd, Logstash, Filebeat and friends.
Log4j still has a place though: Having the ability to use ENV vars or commandline flags to influence log levels and packages is still a nice to have. And one feature that is often overlooked is the ability to set contextual information per request. For example authentication middleware can set a userId or requestId in the request context and every log message within the request handling automatically gets logged with that metadata, avoiding the need to pass all this contextual information manually in every log.info(...) statement.
So, I kick the log level from warn to debug and I see that Spring is booting it because it failed a CORS check. This was much easier than trying to reproduce it in my local system and attach a debugger to it.
There is a lot that goes on beneath and behind the code that a person writes within the libraries. I would contend that the log4j vulnerability is because people didn't realize the extent of what was going on beneath and behind.
Making a developer blind to what goes on inside a library is not the answer. The "what goes on inside of a library" is indeed a concern for the application and the developer and should be made as easy to access as possible.
"This endpoint cannot be accessed in a CORS improper way" is caught in the library/framework level and doesn't even touch my code - there's no exception for me to catch.
Throwing a checked exception for no access rather than returning "false" from a library call because you passed in all upper case on case sensitive role check would be a decision that I wouldn't agree with.
Another example would be "I want to see the sql generated by hibernate" - that's not exception throwing at all, its me trying to debug what the query is and why the performance is awful.
I think that an opaque library in terms of logging is absolutely hell to deal with, I already have my fair share of issues with libraries that don't do enough logging and require painful hours of debugging instead of reading a log...
But, depending on what your program is doing, printf/whatever can be "good enough."
Coming from the C# world, one of the nice things about log4net is that it has a standard exception formatter, and callbacks whenever anything logs to error. This makes it easier to log unexpected errors and phone home when they happen.
logstash is also vulnerable to this though
Just one example.
Compare this to system.err.println("DEBUG: " + var1 + " " + var2 + " " + someThrowable.stackTrace()) -- that creates a StringBuilder, allocates a potentially large String, and then sends it on.
There are numerous performance impacts (improvements) at using a logging framework that doesn't log or allocate a String to log what it doesn't need to.
That's actually a log4j derivative, and imho quite bad.
I don't understand how people would use a library as massive as log4j and not bother looking at what's in the box, and what they need to enable/disable. Blaming it on the opensource product seems weird when you grabbed it for free and didn't even read what's written on the box.
If it weren't for the fear of DDOS attacks, I'd put every webservice in a physical server in a basement somewhere and be done with it. I've been fighting this whole year to simplify and reduce the number of dependencies we use, but it's such an exhausting battle as it goes against the grain of the industry right now, and everyone almost actively works against you: build now, someone else may pay this technical debt.
One of the benefits of working in healthcare is that if it's not on-premesis, it's a non-starter for many organizations.
My company's paranoia of cloud services has paid off several times in terms of security in the last few years, even if the cost in dollars was higher. At this very moment, a vendor is going through a ransomware attack and its SaaS service unavailable. Our locally-hosted version is unaffected.
We only rent other people's computers (cough "cloud" cough) when there is absolutely no alternative, including doing without. On the other hand, it's locked me out of a number of programs and services I'd like to use.
Still, startups have to learn that if you're serious about being in enterprise, having a locally hosted option opens doors. Very lucrative doors.
Can you explain why that is?
I do agree with your point, having been exposed to running openstack on a custom infrastructure for my job has really taught me how much $ you can save if you do things yourself over say aws and that once I picked up the basics of compute, volumes, networking and security. My understanding increased.
I sometimes would find it difficult to keep up with all the aws lingo but doing everything myself has been a really good lesson in keeping things small and lean.
If a startup tries to sell to the enterprise they are likely to die before they make enough in sales and enterprise concerns (such as on prem >> price) aren't usually shared with normal businesses.
Not saying you can't make a fortune selling overpriced products to large companies (hello Oracle) but it isn't a game for a start up.
There are of course many worse causes, but among umbrella organisations which just exist to provide some services to Free Software projects, Apache doesn't stand out as particularly good and I doubt that "Security vulnerabilities due to our lacklustre oversight drove a big increase in donations" is the lesson we ought to provide.
In particular the Apache Way includes: Responsible Oversight and The ASF Security Committee which you might think would be trying to stop stuff like this happening but really exists so that they can say they're responding to whatever new horrible problem has been found and so the system works.
What did the Responsible Oversight do with the idea of adding "lookups" to log4j which by the nature of the language and design of the API can't be safe? They accepted it and cheerfully documented this obviously bad idea. You can still go back and look at their documentation with the Wayback Machine, short of just writing "Look at this amazing remote execution security bug we added to our software" it could not be any clearer.
All money donated to Apache gets spend on their own infrastructure and salaries, etc.
Don't they contribute for the development? Or for what is that salary.
https://www.apache.org/foundation/how-it-works.html
> All participants in ASF projects are volunteers and nobody (not even members or officers) is paid directly by the foundation to do their job. There are many examples of committers who are paid to work on projects, but never by the foundation itself.
Mind you, the download mirrors are also free...
Last time I needed an HTML/CSS framework, I was looking for the "best" open source and free one. I then decided to go with Tailwind and pay the $279 lifetime license fee. Now that I think more about, I'd have been happier with a subscription or paid updates than a "lifetime" license.
So posting images of paper with this string may indeed get hits.
One of the most incredible vulnerabilities ever.
Corporate VPN: "This site is blocked due to a security threat."
IT: Domain too new, so we're blocking it out of abundance of caution.
(Works for blocking new and targeted threats, but you get this false-positive block.)
It bypasses things of this nature ;-)
The number of customers confusing Apache Log4j with Apache Web Server
Is Too Damn High!I will admit that I've used it, though. I have an IRC bot written in Python with a "!calc" command that calls eval(). But I use `ast` to build the syntax tree, then walk it and compare every AST object to a white list so you can only use numbers and math operators. Anything else, such as CALLs or strings will throw an error.
Meanwhile, library developers didn't realize app devs would be feeding untrusted strings to their library.
I guess its debatable who's more at fault. I'd argue a logging library that executes the log entries as code is a hell of a footgun.
(Not a Java dev. Maybe log4j had obvious warnings on the tin? If nothing else, there is a UX lesson here.)
What?!
It's a logging library. I would expect users of it to be feeding user input, so that in the case of a bug, I can look at logs to see what input triggered a bug.
I agree with you, but I did see a couple of days ago someone with the diametrically opposite opinion: that we should never log user input, with a link to https://owasp.org/www-community/attacks/Log_Injection (plus this bug) as the justification.
Nah...logging user input is a must to be able to perform digital forensics and incident response. Certainly knowing exactly how an attack was triggered would help in preventing it in the future.
Just filter the CRs and LFs to prevent log forging, and make sure log files are not accessible from the web app. They should be in /var/log, not in the web root.
Mind you, I also think that original intention was idiotic: Now your java application can't boot up unless your LDAP server is working, and for what? That's the kind of thing that makes global restarts & outage recovery a disaster.
It uses the routing appender that's intended to send logs different ways via string matching and added code that said if the string matching has ${jndi... it should run that jndi code.
The change did what it said it would do. Akin to someone submitting a patch to run eval(log_statment).
That it passed review and was accepted is frightening.
- https://blogs.juniper.net/en-us/enterprise-cloud-and-transfo...
- https://www.govcert.ch/blog/zero-day-exploit-targeting-popul...
It looks like some sort of David v Goliath thing but often I see the template where it implies the pink guy is gonna get owned.
But are you really really happy, mate?This is the Way.
Also noticed we were continously scanned for the vulnerability (random "jndi:ldap" in requests) from different IPs, some from China
> ...relieved to learn all our services are written in ... PHP.
Testimony to just how bad this issue is!Jokes apart, a big kudos to those who were on call :)
My understanding is that Log4Shell vulnerabilities come from parsing `${jndi:ldap:path}` files coming from HTTP requests, which raises the question of why wasn't that input sanitised in the first place.
Aren't `[${}]` in `$GET` and other HTTP headers normally replaced with sanitised strings to prevent these kinds of vulnerabilities?
ie, if the User-Agent is being reflected back to a user on the web page, then HTML entities such as < and > need to be changed to < and > respectively. If it's being put in a SQL query, then quotes (both single and double) and backticks needs to be filtered. Of course, really you should be using parameterized queries so sanitation isn't necessary at all.
If your data is going straight into a log, nobody would expect that data needs to be sanitized, beyond possibly filtering \r and \n to prevent log forging via CRLF injection. I would expect it to not be sanitized, since then it's not clear based on the log what a user actually sent.