Recent Posts
Archives

Posts Tagged ‘Log4J’

PostHeaderIcon [DevoxxFR 2022] Log4Shell: Is It the Apache Foundation’s Fault?

At Devoxx France 2022, Emmanuel Lécharny, Jean-Baptiste Onofré, and Hervé Boutemy, all active contributors to the Apache Software Foundation, tackle the infamous Log4Shell vulnerability that shook the tech world in December 2021. Their collaborative presentation dissects the origins, causes, and responses to the Log4J security flaw, addressing whether the Apache Foundation bears responsibility. By examining the incident’s impact, the trio provides a transparent analysis of open-source security practices, offering insights into preventing future vulnerabilities and fostering community involvement. Their expertise and candid reflections make this a vital discussion for developers and organizations alike.

Unpacking the Log4Shell Incident

Emmanuel, Jean-Baptiste, and Hervé begin by tracing the history of Log4J and the emergence of Log4Shell, a critical vulnerability that allowed remote code execution, impacting countless systems worldwide. They outline the technical root causes, including flaws in Log4J’s message lookup functionality, which enabled attackers to exploit untrusted inputs. The presenters emphasize the rapid response from the Apache community, which released patches and mitigations under intense pressure, highlighting the challenges of maintaining widely-used open-source libraries.

The session provides a sobering look at the incident’s widespread effects, from internal projects to global enterprises. By sharing a detailed post-mortem, the trio illustrates how Log4Shell exposed vulnerabilities in dependency management, urging organizations to prioritize robust software supply chain practices.

Apache’s Security Practices and Challenges

The presenters delve into the Apache Foundation’s approach to managing Common Vulnerabilities and Exposures (CVEs). They explain that the foundation relies on a small, dedicated group of volunteer committers—often fewer than 15 per project—making comprehensive code reviews challenging. Emmanuel, Jean-Baptiste, and Hervé acknowledge that limited resources and the sheer volume of contributions can create gaps, as seen in Log4Shell. However, they defend the open-source model, noting its transparency and community-driven ethos as strengths that enable rapid response to issues.

They highlight systemic challenges, such as the difficulty of auditing complex codebases and the reliance on volunteer efforts. The trio calls for greater community participation, emphasizing that open-source projects like Apache thrive on collective contributions, which can enhance security and resilience.

Solutions and Future Prevention

To prevent future vulnerabilities, Emmanuel, Jean-Baptiste, and Hervé propose several strategies. They advocate for enhanced code review processes, including automated tools and mandatory audits, to catch issues early. They also discuss the potential for increased funding to support open-source maintenance, noting that financial backing could enable more robust security practices. However, they stress that money alone is insufficient; better organizational structures and community engagement are equally critical.

The presenters highlight emerging regulations, such as those in the U.S. and Europe, that hold software vendors accountable for their dependencies. These laws underscore the need for organizations to actively manage their open-source components, fostering a collaborative relationship between developers and users to ensure security.

Engaging the Community

In their closing remarks, the trio urges developers to become active contributors to open-source projects like Apache. They emphasize that even small contributions, such as reporting issues or participating in code reviews, can significantly enhance project security. Jean-Baptiste, Emmanuel, and Hervé invite attendees to engage with the Apache community, noting that projects like Log4J rely on collective effort to thrive. Their call to action underscores the shared responsibility of securing the open-source ecosystem, making it a compelling invitation for developers to get involved.

Hashtags: #Log4Shell #OpenSource #Cybersecurity #DevoxxFR2022 #EmmanuelLécharny #JeanBaptisteOnofré #HervéBoutemy #Apache

PostHeaderIcon How to unit test Logger calls?

Case

Sometimes, you need test the Log4J’s loggers are called with the right parameters. How to perform these tests from with JUnit?

Let’s take an example: how to test these simple class and method?

[java]public class ClassWithLogger {
private static final Logger LOGGER = Logger.getLogger(ClassWithLogger.class);

public void printMessage(Integer foo){
LOGGER.warn("this is the message#" + foo);
}
}[/java]

Example

Define an almost empty Log4J appender, such as:

[java]public class TestAimedAppender extends ArrayList<String> implements Appender {
private final Class clazz;

public TestAimedAppender(Class clazz) {
super();
this.clazz = clazz;
}

@Override
public void addFilter(Filter newFilter) {
}

@Override
public Filter getFilter() {
return null;
}

@Override
public void clearFilters() {
}

public void close() {
}

@Override
public void doAppend(LoggingEvent event) {
add(event.getRenderedMessage());
}

@Override
public String getName() {
return "TestAppender for " + clazz.getSimpleName();
}

@Override
public void setErrorHandler(ErrorHandler errorHandler) {
}

@Override
public ErrorHandler getErrorHandler() {
return null;
}

@Override
public void setLayout(Layout layout) {
}

@Override
public Layout getLayout() {
return null;
}

@Override
public void setName(String name) {
}

public boolean requiresLayout() {
return false;
}
}[/java]

Then create a TestCase with two fields:

[java]public class ClassWithLoggerUnitTest {
private ClassWithLogger classWithLogger;
private TestAimedAppender appender;

}
[/java]

In the setup, remove all appenders, create an instance of our appender, and then add it to the logger related to the class which we want to test:

[java] @Before
public void setUp() throws Exception {
final Logger classWithLoggerLogger = Logger.getLogger(ClassWithLogger.class);
classWithLoggerLogger.removeAllAppenders();
appender = new TestAimedAppender(ClassWithLogger.class);
classWithLoggerLogger.addAppender(appender);
appender.clear();

classWithLogger = new ClassWithLogger();
}[/java]

Then write the following test. The code is documented:

[java] @Test
public void testPrintMessage() throws Exception {
final String expectedMessage = "this is the message#18";

// empty the appender
appender.clear();
// check it is actually empty before any call to the tested class
assertTrue(appender.isEmpty());

// call to the tested class
classWithLogger.printMessage(18);

// check the appender is no more empty
assertFalse(appender.isEmpty());
assertEquals(1, appender.size());
// check the content of the appender
assertEquals(expectedMessage, appender.get(0));

}[/java]

Conclusion

This basic example shows how to perform tests on logger, without overriding the original code or using mocks. Of course, you can improve this basic example, for instance in discriminating owing to the log level (INFO, WARN, ERROR, etc.), use generics, and even any other fantasy ;-).

PostHeaderIcon How to attach a single class to a Log4J appender?

The issue looks simple, but I needed a little search.

Case

I have a log4j config file, with three appenders: INFO, console and trace. I have to add a brand new appender (let’s say: JonathanNewAppender) that will log the events of only one class (let’s say: JonathanComponent). How to configure Log4J to perform that?

Solution

Edit the log4j.properties file.
Do not change the property log4j.rootCategory, do not mention JonathanNewAppender.

[java]log4j.rootCategory=INFO, console, trace[/java]

Add the properties of the appender, for instance: Donner les proprietes de l’appender:

[java]log4j.appender.JonathanNewAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.JonathanNewAppender.Append=true
log4j.appender.JonathanNewAppender.File=logs/prsl-sent-and-received.csv
log4j.appender.JonathanNewAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.JonathanNewAppender.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss}%m%n
log4j.appender.JonathanNewAppender.threshold=INFO[/java]

And here is the trick: add the log level and the actual appender for the new class.

[java]log4j.logger.my.package.name.JonathanComponent=INFO, JonathanNewAppender[/java]

Indeed, the only field of a logger to be mandatory is the log level. When the appender is specified, it will be taked in account. Otherwise, the logger will be attached all the appenders available in log4j.rootCategory property.

PostHeaderIcon Useful DTD

DTDs are useful when your XML editor take them in account: detecting errors, suggestions, complete statements… For instance, I save much time with IntelliJ IDEA automatic completion ; unlike, Eclipse amazingly does not implement this feature.

Here is a list of some widely used DTDs:

File DTD
weblogic-application.xml [xml]<!DOCTYPE weblogic-application PUBLIC "-//BEA Systems, Inc.//DTD WebLogic Application 7.0.0//EN" "http://www.oracle.com/technology/weblogic/weblogic-application/1.1/weblogic-application.xsd">[/xml]
weblogic-application.xml [xml]<!DOCTYPE weblogic-application PUBLIC "-//BEA Systems, Inc.//DTD WebLogic Application 7.0.0//EN" "http://www.oracle.com/technology/weblogic/weblogic-application/1.1/weblogic-application.xsd">[/xml]
web.xml [xml]<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >[/xml]
*.hbm.xml [xml]<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">[/xml]
GWT modules [xml]<!DOCTYPE module SYSTEM "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">[/xml]
GWT UI [xml]<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">[/xml]
Tangosol / Oracle Coherence [xml]<!DOCTYPE coherence SYSTEM "coherence.dtd">[/xml]
Log4J [xml]<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">[/xml]

Tangosol and Log4J DTDs are included within their distribution JARs: you have to extract them or to give their path to IntelliJ IDEA.

PostHeaderIcon java.io.NotSerializableException: org.apache.log4j.Logger

Case

I use Oracle Coherence (Tangosol) as distributed cache for a given class. This class contains a non-static Log4J’s Logger as field.
(what a Logger does in an “POJO” is not obvious and requires further development ; let’s say it is used during the development phase, but has nothing to do in a POJO and should be removed later).
When Tangosol tries to put the object in cache, I get this error:

[java]java.io.NotSerializableException: org.apache.log4j.Logger[/java]

Complete stacktrace

java.io.NotSerializableException: org.apache.log4j.Logger
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
        at com.tangosol.util.ExternalizableHelper.writeSerializable(ExternalizableHelper.java:2181)
        at com.tangosol.util.ExternalizableHelper.writeObjectInternal(ExternalizableHelper.java:2603)
        at com.tangosol.util.ExternalizableHelper.serializeInternal(ExternalizableHelper.java:2529)
        at com.tangosol.util.ExternalizableHelper.toBinary(ExternalizableHelper.java:206)
        at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.DistributedCache$ConverterValueToBinary.convert(DistributedCache.CDB:3)
        at com.tangosol.util.ConverterCollections$ConverterMap.put(ConverterCollections.java:1566)
        at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.DistributedCache$ViewMap.put(DistributedCache.CDB:1)
        at com.tangosol.coherence.component.util.SafeNamedCache.put(SafeNamedCache.CDB:1)
        at com.lalou.jonathan.business.cache.TypedEhCache.put(TypedEhCache.java:73)
        at com.lalou.jonathan.business.cache.TypedEhCache.setInCache(TypedEhCache.java:58)
        at com.lalou.jonathan.business.StringToRequestListTransformer.transform(JonathanTransformer.java:104)
        at org.mule.transformer.AbstractMessageAwareTransformer.doTransform(AbstractMessageAwareTransformer.java:68)
        at org.mule.transformer.AbstractTransformer.transform(AbstractTransformer.java:254)
        at org.mule.DefaultMuleMessage.applyAllTransformers(DefaultMuleMessage.java:621)
        at org.mule.DefaultMuleMessage.applyTransformers(DefaultMuleMessage.java:582)
        at org.mule.DefaultMuleMessage.applyTransformers(DefaultMuleMessage.java:575)
        at org.mule.DefaultMuleEvent.transformMessage(DefaultMuleEvent.java:326)
        at org.mule.DefaultMuleEvent.transformMessage(DefaultMuleEvent.java:321)
        at org.mule.component.simple.PassThroughComponent.doInvoke(PassThroughComponent.java:27)
        at org.mule.component.AbstractComponent.invokeInternal(AbstractComponent.java:133)
        at org.mule.component.AbstractComponent.invoke(AbstractComponent.java:161)
        at org.mule.service.AbstractService.invokeComponent(AbstractService.java:929)
        at org.mule.model.seda.SedaService.access$100(SedaService.java:56)
        at org.mule.model.seda.SedaService$ComponentStageWorker.run(SedaService.java:574)
        at org.mule.work.WorkerContext.run(WorkerContext.java:310)
        at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
        at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:575)
        at java.lang.Thread.run(Thread.java:619)

Fix

Declare the Logger as static:

[java]private final Logger LOG = Logger.getLogger(CsvFileObject.class);[/java]

In my case, the issue was fixed. If it is not, try to declare the Logger as static transient, I assume it could help.