Necessary and sufficient validations upon application init - java

I have a new puzzle for you :-).
I was thinking on how should an application handle his own start up. Like : checking for required libraries, correct versions, database connectivity, database compatibility, etc. To be specific, here is the test case. I use SWT and Log4J, for obvious reasons. Now, the questions :
Should the app check itself for the required dependencies? If yes, should the user be given specific details of what it's missing? Or just a message, and details to the logs?
What if the log4J library is unavailable?
What is the best to do the test? Verifying the file existance (using file.exists(), at specified path), or loading a class, say Class.forName("org.apache.log4j.Logger")? What should be the proper order to do the checks? For instance, if i test for SWT, i have no idea if logger is available or not, and the error will occur when i try to access that. Backwards, if i test for the logger 1st : a) The lib could be unavailable - i cannot log the error; b) SWT could be unavailable - unable to display the user message.
I've discovered apache.commons.lang framework today, and i find very useful the method org.apache.commons.lang.SystemUtils.isJavaVersionAtLeast(Float value)
, and manny others, i am sure. However, importing too much libs to your project dont make it hard to maintain? Versions change, compatibilities are lost, eg. one cannot control a 3rd party developement style or direction.
Thank u for your answers.

I agree with your need. Checking for required runtime environment provides:
immediate feedback, instead of randomly breaking when accessing some functionnality
hopefully more skilled user, as the immediate feedback is available to the guy that is installing the software, hopefully more skilled than an average user, or at least less confident (installing is always a special operation). A more skilled user is less disturbed if the error is coming in the console, he doesn't depend on a graphical interface.
improved reporting : the error message can be explicit (you're in charge), while default error messages come in many flavours (they are not always that helpful on 1. what's wrong 2. suggesting a fix).
But please note that the runtime requirements could be checked in two situations:
when installing : long verifications are always acceptable ; if a library is not here, a required database or WebService is not accessible, it won't be here at runtime either, so you can complain immediately.
when starting the execution : you can verify again (and some verifications may only happen at that point)
This suggests creating an installer for your application.
Potentially, errors would not all be blocking for the installation. Some would rather accumulate as a list of tasks to be done after installation, maybe nicely formatted in a file with all reference information.
Here, we once again hit the notion of error level in validation (similar to what happens for Log4j) : some validation errors are at fatal level, others are errors, possibly also warnings ...
In our projects, we have some sort of initialization and validation going on on startup. Based on our day-to-day experience, I would suggest the following:
When the application gets big, you don't want to have all init centralized in one class, so we have a modular structure.
A small kernel is configured with a list of modules classes. It's whole init sequence is under strict control, ready for any exceptions (translating them to appropriate messages, but memorizing the stack traces that are so useful to the developpers), making no assumption on the available libraries and so on... CheckStyle can be configured specially for this code.
The interface (of course, abstract class is possible) that the modules implement typically have several initialization methods. They could be:
getDependencies : returns a list of modules that this one depends on.
startup : when the whole application is starting. This will be called only once during startup, and cannot be called again.
start : when the module gets ready for regular operation
stop : reverse from start
shutdown : reverse from startup.
The kernel instanciates each of the module in turn. Then he calls one init method on all of them, then another init method and so on as needed. Each init method can:
signal error conditions (using levels, like Log4J).
an exception thrown would be caught by the kernel, and translated to an error condition
consult another module for its status (because dependencies are the general case), and react accordingly. If needed, the dependencies could be made declaratively.
The kernel takes care of module dependencies generically:
He sorts the modules so that dependencies are respected.
He doesn't initialize a module if one of its dependencies couldn't make it.
If asked to stop a module, he will first stop the modules that depends on it.
A nice feature of this kernel approach is that it is easy to aggregate the errors, at various levels (although fatal could stop it), and report all of them at the end, using whatever means is available (SWT or not, Log4J or not ...). So instead of discovering the problems one after the other, and having to start again each time, you could deliver in one blow (nicely prioritized of course).
Concerning your precise questions:
Should the app check itself for the required dependencies?
Yes (see higher)
If yes, should the user be given specific details of what it's missing? Or just a message, and details to the logs?
As said higher, when installing the user is more prepared to deal with this.
When starting, we use an easy message for the end-user, but give access to the full stack traces for the developper (we have a button that copies in the clipboard the application environment, the stack traces and so on).
What if the log4J library is unavailable?
Log without it (see higher).
What is the best to do the test? Verifying the file existance (using file.exists(), at specified path), or loading a class, say Class.forName("org.apache.log4j.Logger")?
I would load a class. But if it failed, I might check the file existence on disk to give a improved message, including "how to fix".
What should be the proper order to do the checks? For instance, if i test for SWT, i have no idea if logger is available or not, and the error will occur when i try to access that. Backwards, if i test for the logger 1st : a) The lib could be unavailable - i cannot log the error; b) SWT could be unavailable - unable to display the user message.
As I said higher, I suggest these low-level errors get accumulated in a small area of code (kernel), where you could use anything that is available to display them. If nothing is available, you could simply log in the console without Log4J.

The short answer is no. The JVM appropriately handles this functionality on initialization, or at runtime. If a required class is not found on the classpath, a ClassNotFoundException will be thrown. If a class was found, but a required method was not, a NoSuchMethodException is thrown.

Regarding 1 through 3 , there are 2 main use cases here:
application packaging is under your control, and can make sure that all required dependencies are packaged properly. Run-time validations are not useful here.
application packaging is not under your control, and you deliver the main jar and the instructions on what the requirements are. Run-time validations might be useful, but someone who wants to package your application usually has enough skill to understand what a ClassNotFoundException: org.apache.logging.LogManager means.
Regarding 4, as long as you keep the same version of the dependency included in your project, you will have no problems in keeping control. Upgrading to a newer version is a conscious decision, which requires thought and testing.

Related

log4j exploit - is it still vulnerable if log4j is maintained in classpath but not actually used in code?

This is regarding vulnerability reported with CVE-2021-44228 against the log4j-core jar and has been fixed in Log4J v2.15.0.
We use Logback API via slf4j. This is confirmed with below code.
final StaticLoggerBinder binder = StaticLoggerBinder.getSingleton();
System.out.println(binder.getLoggerFactory());
System.out.println(binder.getLoggerFactoryClassStr());
//output:
//ch.qos.logback.classic.LoggerContext[default]
//ch.qos.logback.classic.util.ContextSelectorStaticBinder
mvn dependency:tree shows log4j-core API (version <2.15) in classpath (both direct & transitive dependency).
Is the application still vulnerable due to maintaining log4j-core in classpath? Thank you!
In order for a vulnerability to be a risk to you, several things need to come together:
the corresponding library exists in your environment
the corresponding library calls do happen in your environment at runtime
3rd party users figure a way to get their (unchecked) input to that library call
Nobody here can tell you whether "2." and ".3" are applicable in your environment.
But: when you eliminate 1., you know that "2." and "3." are no longer possible. Or the other way round, as long as you 100% convinced that there is no path how a user can enter data into your system that makes it to the corresponding API, then you should be fine even with leaving the library sitting in your environment. But as said, having the library is the mandatory first element of the chain. So while that is present, it is possible that somebody writes code tomorrow that gets you to "2" and "3"!
Thus, keep in mind the perspective of higher management: most likely, the business decision might be: reduce the risk to 0, so make sure you don't even have the corresponding JAR sitting on your machines.
In my bigcorp environment, orders were pretty simple: don't waste any time analysing whether your code uses the corresponding interfaces. When your projects contain the vulnerable JAR, upgrade it immediately. Period.

Block instances of a class at the JVM level?

Is there a way to configure the JVM to block instances of a class being created?
I'd like to do this to ensure no service running in the JVM is allowed to create instances of a class that has been identified as a security risk in a CVE, lets call that class BadClass.
NOTE: I'm looking for a general solution, so the following is purely additional information. I would normally address this by switching the library out, or upgrading it to a version that doesn't have the exploit, but it's part of a larger library that wont be addressing the issue for some time. So I'm not even using BadClass anywhere, but want to completely block it.
I do not know a JVM parameter, but here's some alternatives that might pout you in a position that solve your requirements:
You can write a CustomClassLoader that gives you fine control on what to do. Normal use cases would be plugin loading etc. In your case this is more security governance on devops level.
If you have a CICD pipeline with integration tests you could also start the JVM with -verbose:class parameter and see which classes are loaded when running your tests. Seem a bit hacky, but maybe suits your use case. Just throwing everything into the game, it's up to you judging about the best fit.
Depending on your build system (Maven?) you could restrict building applications just on your private cached libs. So you should have full control on it and put a library - review layer in between. This would also share responsibility between devs and the repository admins.
A distinct non-answer: Do not even try!
What if that larger library that has this dependency wants to call that method? What should happen then?
In other words, what is your blocking supposed to do?
Throw some Error instance, that leads to a teardown of the JVM?
Return null, so that (maybe much later) other code runs into a NPE?
Remember: that class doesn't exist in a void. There is other code invoking it. That code isn't prepared for you coming in, and well, doing what again?!
I think there are no good answers to these questions.
So, if you really want to "manipulate" things:
Try sneaking in a different version of that specific class into your classpath instead. Either an official one, that doesn't have the security issue, or something that complies to the required interface and that does something less harmful. Or, if you dare going down that path, do as the other answer suggests and get into "my own classloader" business.
In any case, your first objective: get clean on your requirements here. What does blocking mean?!
Have you considered using Java Agent?
It can intercept class loading in any classloader, and manipulate it's content before the class is actually loaded. Then, you may either modify the class to remove/fix it's bugs, or return dummy class that would throw error in static initializer.

Unit/integration tests that verify the properties or configurations

Does it make sense to write unit/integration tests that verify the properties or configurations, since any medium to highly complex applications include a lot of configurations (via YAML or properties files)?
Many of these configurations derive the run time behaviour even if they are used by the underlying libraries or frameworks. Would it be a sensible idea to verify that the configurations are correctly used at runtime?
One pro-argument is since there is no compiler safety, we need to somehow verify if the configurations are dictating the behaviour correctly.
The con argument is, are we verifying the underlying frameworks implementation?
Testing just the configuration file might not be enough as it does not guarantee if the configuration will be correctly employed at runtime (there could be typos or other similar mistakes).
No. Unit tests will tell you what works in the test harness, which is—and should be—different from what is in production.
You hit the nail on the head when you said you want to verify the configuration. Testing and verification are two entirely different things. If you have a way to verify the runtime configuration in production, it will also help you diagnose runtime misbehavior.
There are lots of ways to verify the runtime configuration. The simplest and best is logging (e.g. "2016-09-24 10:13:00 connecting to http://my-configured-server.example.com to get user token"). Don't just dump the configuration to the log file-- that's not end-to-end verification-- sprinkle configuration details into log messages.
Configuration issues are often all-or-nothing; if you don't get the configuration just right, nothing happens and you don't know why. (This is especially true with functional programming.) Logging can tell you not only what the configuration is, but at what moment the configuration fails.
There are other clever ways to sprinkle configuration details into the runtime. For example, attaching verbose runtime details to error messages, especially email where you have more room than in logs. Or a debug mode where hovering over a UI element tells you the class and other facts about that element.
Integration tests (the components work when plugged together) and smoke tests (some complete configuration does something right) can be important-- I would say necessary if you deploy without manual testing-- but they are no substitute for runtime verification.
This is pretty reasonable IMHO, especially when talking ever growing virtualization. In one of the previous projects I was involved - a mSOA platform, which supported (back then) hundreds of web sites with ease, we found out that most of the issues were due to exactly
configurations are correctly used at runtime
The Orchard recepies were messed up a lot of the the times, as well. So a point for Docker containers. It is pretty much straightforward to test the infrastructure and its configuration your product/service is using. I've used successfully serverspec.

tracking the flow of classes called while debugging the project

I have a query that is I am debuging a project in eclipse and I have to enchance its functionality in near future the project is in mostly in core java and all the classes are interlinked in the whole flow.
As i am debuging the project so as per the flow it is switiching between different classes now I want to record all the claases name from which it pass , so in order to remember the flow so thatr is the one way , so for this either I can go for logs, or is there any softwate or plugin that can be installed in eclipse that record to which varios classes I passesand which methods were called in which order other thanm logs please advise.
Probably the best thing is to log the relevant information you need.
Logs have the advantage of recording exactly what you need (So not only the names of the class you traverse but also relevant variable values) and you can run them even outside from Eclipse, which it is sometimes useful when you have to track down bugs in the production environment.

Is it ok to log the source class name and method name in a java product?

i am currently working on a java application for some network monitoring tool. In my code i am supposed to use logging a lot. Since its a network management software, the information in logs is quite useful to the user hence its compulsory to use them. But now I am bit confused with what kind of logger method i should prefer. Right now i am using Logger.lop(...//...) since with its help we are also logging the class name and method so its becoming very easy for me (developers) to debug the code and find the error. But finally I am confused should i deliver it to the end user with the same logging mechanism??? Is it any harm to let your user know what kind of class is executing currently , in which method error has occured. I have seen many times in many product in exception handling stacktrace is used so normally we get class name as well. So is there is no problem to let enduser know what your class name and method is??
Before considering the security implications of it, consider the performance. In most logging systems, getting the actual classname and method name dynamically by the logging facility requires reflection and dramatically slows down the logging - usually a synchronous operation. My guess is that in a network monitoring application, you really don't want that.
If you're hard-coding the method name into the log message (either by making it part of the message or by the category), that's a different story. As a security person, I don't consider it to be that big of a deal - if your code is in Java, it can be reversed anyhow, so your code should operate in such a way that it would be secure even if the code was given away.
All that being said, you could either use a different logging configuration for development and production, or those fine-grained messages could go in debug, trace, etc. If you're using log4j, it's generally advisable to use isDebugEnabled to wrap any logging statements which include anything dynamically-calculated as those get calculated before the logging statement determines whether it's enabled.
log4j/logback/slf4j allow you to have different formats for different appenders. For development you can enable a console appender where you include the class name in the format, while for the end-users you can omit it (for a file appender)
It's worth mentioning that such logging is performance costly in Java, contrary to C++ where it is usually implemented with preprocessor. Fortunately, with log4j/logback you can switch it on and off — follow Bozho's advice.

Categories