LOG4J2-3056 Refactor MD5 usage for sharing sensitive information (#484)
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
index 31cbf7e..75cd2d4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
@@ -16,19 +16,17 @@
*/
package org.apache.logging.log4j.util;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
-
-import org.apache.logging.log4j.util.Strings;
+import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
/**
*
*/
public final class NameUtil {
- private static final int MASK = 0xff;
-
- private NameUtil() {
- }
+ private NameUtil() {}
public static String getSubName(final String name) {
if (Strings.isEmpty(name)) {
@@ -38,22 +36,41 @@
return i > 0 ? name.substring(0, i) : Strings.EMPTY;
}
- public static String md5(final String string) {
+ /**
+ * Calculates the <a href="https://en.wikipedia.org/wiki/MD5">MD5</a> hash
+ * of the given input string encoded using the default platform
+ * {@link Charset charset}.
+ * <p>
+ * <b>MD5 has severe vulnerabilities and should not be used for sharing any
+ * sensitive information.</b> This function should only be used to create
+ * unique identifiers, e.g., configuration element names.
+ *
+ * @param input string to be hashed
+ * @return string composed of 32 hexadecimal digits of the calculated hash
+ */
+ public static String md5(final String input) {
+ Objects.requireNonNull(input, "input");
try {
+ final byte[] inputBytes = input.getBytes();
final MessageDigest digest = MessageDigest.getInstance("MD5");
- digest.update(string.getBytes());
- final byte[] bytes = digest.digest();
- final StringBuilder md5 = new StringBuilder();
+ final byte[] bytes = digest.digest(inputBytes);
+ final StringBuilder md5 = new StringBuilder(bytes.length * 2);
for (final byte b : bytes) {
- final String hex = Integer.toHexString(MASK & b);
+ final String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
md5.append('0');
}
md5.append(hex);
}
return md5.toString();
- } catch (final Exception ex) {
- return string;
+ }
+ // Every implementation of the Java platform is required to support MD5.
+ // Hence, this catch block should be unreachable.
+ // See https://docs.oracle.com/javase/8/docs/api/java/security/MessageDigest.html
+ // for details.
+ catch (final NoSuchAlgorithmException error) {
+ throw new RuntimeException(error);
}
}
+
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
index 76e9c31..f746f6a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
@@ -19,7 +19,6 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
-import org.apache.logging.log4j.util.NameUtil;
import org.apache.logging.log4j.util.StringBuilders;
import org.apache.logging.log4j.util.Strings;
@@ -86,7 +85,7 @@
}
private void debugLog(final Object value) {
- final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+ final Object debugValue = annotation.sensitive() ? "*****" : value;
StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
index dc3aa06..d70080e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
@@ -20,7 +20,6 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.inject.AbstractConfigurationInjector;
-import org.apache.logging.log4j.util.NameUtil;
import org.apache.logging.log4j.util.StringBuilders;
import java.util.Optional;
@@ -44,7 +43,7 @@
}
private void debugLog(final Object value) {
- final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+ final Object debugValue = annotation.sensitive() ? "*****" : value;
StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
}
}
\ No newline at end of file
diff --git a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
index 6eb207e..179096c 100644
--- a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
+++ b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
@@ -28,7 +28,6 @@
import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
-import org.apache.logging.log4j.util.NameUtil;
import org.apache.logging.log4j.util.Strings;
import org.lightcouch.CouchDbClient;
import org.lightcouch.CouchDbProperties;
@@ -106,7 +105,6 @@
final CouchDbProperties properties = (CouchDbProperties) object;
client = new CouchDbClient(properties);
description = "uri=" + client.getDBUri() + ", username=" + properties.getUsername()
- + ", passwordHash=" + NameUtil.md5(password + CouchDbProvider.class.getName())
+ ", maxConnections=" + properties.getMaxConnections() + ", connectionTimeout="
+ properties.getConnectionTimeout() + ", socketTimeout=" + properties.getSocketTimeout();
} else if (object == null) {
@@ -149,8 +147,7 @@
}
client = new CouchDbClient(databaseName, false, protocol, server, portInt, username, password);
- description = "uri=" + client.getDBUri() + ", username=" + username + ", passwordHash="
- + NameUtil.md5(password + CouchDbProvider.class.getName());
+ description = "uri=" + client.getDBUri() + ", username=" + username;
} else {
LOGGER.error("No factory method was provided so the database name is required.");
return null;
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEmbeddedManager.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEmbeddedManager.java
index 7147a41..c20dcfb 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEmbeddedManager.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEmbeddedManager.java
@@ -82,6 +82,17 @@
throw new IllegalArgumentException("Cannot configure both Agents and Properties.");
}
+ final String managerName = createManagerName(name, agents, properties);
+ return getManager(managerName, factory,
+ new FactoryData(name, agents, properties, batchSize, dataDir));
+
+ }
+
+ private static String createManagerName(
+ final String name,
+ final Agent[] agents,
+ final Property[] properties) {
+
final StringBuilder sb = new StringBuilder();
boolean first = true;
@@ -106,8 +117,9 @@
}
sb.append(NameUtil.md5(props.toString()));
}
- return getManager(sb.toString(), factory,
- new FactoryData(name, agents, properties, batchSize, dataDir));
+
+ return sb.toString();
+
}
@Override
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
index d38cab8..52e05b1 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
@@ -32,7 +32,6 @@
import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
-import org.apache.logging.log4j.util.NameUtil;
import org.apache.logging.log4j.util.Strings;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
@@ -177,8 +176,7 @@
MongoCredential mongoCredential = null;
description = "database=" + databaseName;
if (Strings.isNotEmpty(userName) && Strings.isNotEmpty(password)) {
- description += ", username=" + userName + ", passwordHash="
- + NameUtil.md5(password + MongoDb3Provider.class.getName());
+ description += ", username=" + userName;
mongoCredential = MongoCredential.createCredential(userName, databaseName, password.toCharArray());
}
try {
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java
index af1144f..87aad2e 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginAttributeInjector.java
@@ -81,7 +81,7 @@
}
private void debugLog(final Object value) {
- final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+ final Object debugValue = annotation.sensitive() ? "*****" : value;
StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java
index f1d734d..adf41f6 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/inject/PluginBuilderAttributeInjector.java
@@ -38,7 +38,7 @@
}
private void debugLog(final Object value) {
- final Object debugValue = annotation.sensitive() ? NameUtil.md5(value + getClass().getName()) : value;
+ final Object debugValue = annotation.sensitive() ? "*****" : value;
StringBuilders.appendKeyDqValue(debugLog, name, debugValue);
}
}
diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java
index d44a35d..f8c0154 100644
--- a/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java
+++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java
@@ -108,7 +108,30 @@
protocol = "smtp";
}
+ final String managerName = createManagerName(to, cc, bcc, from, replyTo, subject, protocol, host, username, password, isDebug, filterName);
+ final Serializer subjectSerializer = PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(subject).build();
+
+ return getManager(managerName, FACTORY, new FactoryData(to, cc, bcc, from, replyTo, subjectSerializer,
+ protocol, host, port, username, password, isDebug, numElements, sslConfiguration));
+
+ }
+
+ private static String createManagerName(
+ final String to,
+ final String cc,
+ final String bcc,
+ final String from,
+ final String replyTo,
+ final String subject,
+ final String protocol,
+ final String host,
+ final String username,
+ final String password,
+ final boolean isDebug,
+ final String filterName) {
+
final StringBuilder sb = new StringBuilder();
+
if (to != null) {
sb.append(to);
}
@@ -144,11 +167,9 @@
sb.append(isDebug ? ":debug:" : "::");
sb.append(filterName);
- final String name = "SMTP:" + NameUtil.md5(sb.toString());
- final Serializer subjectSerializer = PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(subject).build();
+ final String hash = NameUtil.md5(sb.toString());
+ return "SMTP:" + hash;
- return getManager(name, FACTORY, new FactoryData(to, cc, bcc, from, replyTo, subjectSerializer,
- protocol, host, port, username, password, isDebug, numElements, sslConfiguration));
}
/**
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ad73bf7..56f48ce 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -170,6 +170,9 @@
</release>
<release version="2.15.0" date="2021-MM-DD" description="GA Release 2.15.0">
<!-- ADDS -->
+ <action issue="LOG4J2-3056" dev="vy" type="add" due-to="Marcono1234">
+ Refactor MD5 usage for sharing sensitive information.
+ </action>
<action issue="LOG4J2-3004" dev="vy" type="add">
Add plugin support to JsonTemplateLayout.
</action>