238 lines
13 KiB
Diff
238 lines
13 KiB
Diff
From 7fe72d62fcb9246be792b946e405e1d40d402780 Mon Sep 17 00:00:00 2001
|
|
From: Ralph Goers <rgoers@apache.org>
|
|
Date: Sat, 4 Dec 2021 20:59:39 -0700
|
|
Subject: [PATCH] LOG4J2-3201 - Limit the protocols JNDI can use by default.
|
|
Limit the servers and classes that can be accessed via LDAP.
|
|
|
|
---
|
|
.../logging/log4j/core/net/JndiManager.java | 62 ++++++++++---------
|
|
.../logging/log4j/core/util/NetUtils.java | 4 ++
|
|
src/changes/changes.xml | 3 +
|
|
src/site/xdoc/manual/appenders.xml | 27 ++++++++
|
|
src/site/xdoc/manual/configuration.xml.vm | 26 ++++++++
|
|
src/site/xdoc/manual/extending.xml | 5 +-
|
|
src/site/xdoc/manual/lookups.xml | 7 +++
|
|
7 files changed, 103 insertions(+), 31 deletions(-)
|
|
|
|
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
|
|
index b392b93..2d7604f 100644
|
|
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
|
|
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/JndiManager.java
|
|
@@ -209,43 +209,45 @@ public class JndiManager extends AbstractManager {
|
|
public synchronized <T> T lookup(final String name) throws NamingException {
|
|
try {
|
|
URI uri = new URI(name);
|
|
- if (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {
|
|
- LOGGER.warn("Log4j JNDI does not allow protocol {}", uri.getScheme());
|
|
- return null;
|
|
- }
|
|
- if (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {
|
|
- if (!allowedHosts.contains(uri.getHost())) {
|
|
- LOGGER.warn("Attempt to access ldap server not in allowed list");
|
|
+ if (uri.getScheme() != null) {
|
|
+ if (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {
|
|
+ LOGGER.warn("Log4j JNDI does not allow protocol {}", uri.getScheme());
|
|
return null;
|
|
}
|
|
- Attributes attributes = this.context.getAttributes(name);
|
|
- if (attributes != null) {
|
|
- // In testing the "key" for attributes seems to be lowercase while the attribute id is
|
|
- // camelcase, but that may just be true for the test LDAP used here. This copies the Attributes
|
|
- // to a Map ignoring the "key" and using the Attribute's id as the key in the Map so it matches
|
|
- // the Java schema.
|
|
- Map<String, Attribute> attributeMap = new HashMap<>();
|
|
- NamingEnumeration<? extends Attribute> enumeration = attributes.getAll();
|
|
- while (enumeration.hasMore()) {
|
|
- Attribute attribute = enumeration.next();
|
|
- attributeMap.put(attribute.getID(), attribute);
|
|
+ if (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {
|
|
+ if (!allowedHosts.contains(uri.getHost())) {
|
|
+ LOGGER.warn("Attempt to access ldap server not in allowed list");
|
|
+ return null;
|
|
}
|
|
- Attribute classNameAttr = attributeMap.get(CLASS_NAME);
|
|
- if (attributeMap.get(SERIALIZED_DATA) != null) {
|
|
- if (classNameAttr != null) {
|
|
- String className = classNameAttr.get().toString();
|
|
- if (!allowedClasses.contains(className)) {
|
|
- LOGGER.warn("Deserialization of {} is not allowed", className);
|
|
+ Attributes attributes = this.context.getAttributes(name);
|
|
+ if (attributes != null) {
|
|
+ // In testing the "key" for attributes seems to be lowercase while the attribute id is
|
|
+ // camelcase, but that may just be true for the test LDAP used here. This copies the Attributes
|
|
+ // to a Map ignoring the "key" and using the Attribute's id as the key in the Map so it matches
|
|
+ // the Java schema.
|
|
+ Map<String, Attribute> attributeMap = new HashMap<>();
|
|
+ NamingEnumeration<? extends Attribute> enumeration = attributes.getAll();
|
|
+ while (enumeration.hasMore()) {
|
|
+ Attribute attribute = enumeration.next();
|
|
+ attributeMap.put(attribute.getID(), attribute);
|
|
+ }
|
|
+ Attribute classNameAttr = attributeMap.get(CLASS_NAME);
|
|
+ if (attributeMap.get(SERIALIZED_DATA) != null) {
|
|
+ if (classNameAttr != null) {
|
|
+ String className = classNameAttr.get().toString();
|
|
+ if (!allowedClasses.contains(className)) {
|
|
+ LOGGER.warn("Deserialization of {} is not allowed", className);
|
|
+ return null;
|
|
+ }
|
|
+ } else {
|
|
+ LOGGER.warn("No class name provided for {}", name);
|
|
return null;
|
|
}
|
|
- } else {
|
|
- LOGGER.warn("No class name provided for {}", name);
|
|
+ } else if (attributeMap.get(REFERENCE_ADDRESS) != null
|
|
+ || attributeMap.get(OBJECT_FACTORY) != null) {
|
|
+ LOGGER.warn("Referenceable class is not allowed for {}", name);
|
|
return null;
|
|
}
|
|
- } else if (attributeMap.get(REFERENCE_ADDRESS) != null
|
|
- || attributeMap.get(OBJECT_FACTORY) != null) {
|
|
- LOGGER.warn("Referenceable class is not allowed for {}", name);
|
|
- return null;
|
|
}
|
|
}
|
|
}
|
|
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NetUtils.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NetUtils.java
|
|
index b9a01ae..6adac59 100644
|
|
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NetUtils.java
|
|
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NetUtils.java
|
|
@@ -83,6 +83,10 @@ public final class NetUtils {
|
|
}
|
|
}
|
|
|
|
+ /**
|
|
+ * Returns all the local host names and ip addresses.
|
|
+ * @return The local host names and ip addresses.
|
|
+ */
|
|
public static List<String> getLocalIps() {
|
|
List<String> localIps = new ArrayList<>();
|
|
localIps.add("localhost");
|
|
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
|
|
index 9c44684..f2d9c57 100644
|
|
--- a/src/changes/changes.xml
|
|
+++ b/src/changes/changes.xml
|
|
@@ -30,6 +30,9 @@
|
|
- "remove" - Removed
|
|
-->
|
|
<release version="2.13.2" date="2020-04-23" description="GA Release 2.13.2">
|
|
+ <action issue="LOG4J2-3201" dev="rgoers" type="fix">
|
|
+ Limit the protocols JNDI can use by default. Limit the servers and classes that can be accessed via LDAP.
|
|
+ </action>
|
|
<action issue="LOG4J2-2824" dev="rgoers" type="fix" due-to="CrazyBills">
|
|
Implement requiresLocation in GelfLayout to reflect whether location information is used in the message Pattern.
|
|
</action>
|
|
diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml
|
|
index ab40094..267f54f 100644
|
|
--- a/src/site/xdoc/manual/appenders.xml
|
|
+++ b/src/site/xdoc/manual/appenders.xml
|
|
@@ -1542,6 +1542,33 @@ public class ConnectionFactory {
|
|
<th>Default</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
+ <tr>
|
|
+ <td>allowdLdapClasses</td>
|
|
+ <td>String</td>
|
|
+ <td>null</td>
|
|
+ <td>
|
|
+ A comma separated list of fully qualified class names that may be accessed by LDAP. The classes
|
|
+ must implement Serializable. Only applies when the JMS Appender By default only Java primative classes are allowed.
|
|
+ </td>
|
|
+ </tr>
|
|
+ <tr>
|
|
+ <td>allowdLdapHosts</td>
|
|
+ <td>String</td>
|
|
+ <td>null</td>
|
|
+ <td>
|
|
+ A comma separated list of host names or ip addresses that may be accessed by LDAP. By default only
|
|
+ the local host names and ip addresses are allowed.
|
|
+ </td>
|
|
+ </tr>
|
|
+ <tr>
|
|
+ <td>allowdJndiProtocols</td>
|
|
+ <td>String</td>
|
|
+ <td>null</td>
|
|
+ <td>
|
|
+ A comma separated list of protocol names that JNDI will allow. By default only java, ldap, and ldaps
|
|
+ are the only allowed protocols.
|
|
+ </td>
|
|
+ </tr>
|
|
<tr>
|
|
<td>factoryBindingName</td>
|
|
<td>String</td>
|
|
diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm
|
|
index a3da3b8..402a96c 100644
|
|
--- a/src/site/xdoc/manual/configuration.xml.vm
|
|
+++ b/src/site/xdoc/manual/configuration.xml.vm
|
|
@@ -1960,6 +1960,32 @@ public class AwesomeTest {
|
|
before falling back to the default class loader.
|
|
</td>
|
|
</tr>
|
|
+ <tr>
|
|
+ <td><a name="allowedLdapClasses"/>log4j2.allowedLdapClasses</td>
|
|
+ <td>LOG4J_ALLOWED_LDAP_CLASSES</td>
|
|
+ <td> </td>
|
|
+ <td>
|
|
+ System property that specifies fully qualified class names that may be accessed by LDAP. The classes
|
|
+ must implement Serializable. By default only Java primative classes are allowed.
|
|
+ </td>
|
|
+ </tr>
|
|
+ <tr>
|
|
+ <td><a name="allowedLdapHosts"/>log4j2.allowedLdapHosts</td>
|
|
+ <td>LOG4J_ALLOWED_LDAP_HOSTS</td>
|
|
+ <td> </td>
|
|
+ <td>
|
|
+ System property that adds host names or ip addresses that may be access by LDAP. By default it only allows
|
|
+ the local host names and ip addresses.
|
|
+ </td>
|
|
+ </tr>
|
|
+ <tr>
|
|
+ <td><a name="allowedJndiProtocols"/>log4j2.allowedJndiProtocols</td>
|
|
+ <td>LOG4J_ALLOWED_JNDI_PROTOCOLS</td>
|
|
+ <td> </td>
|
|
+ <td>
|
|
+ System property that adds protocol names that JNDI will allow. By default it only allows java, ldap, and ldaps.
|
|
+ </td>
|
|
+ </tr>
|
|
<tr>
|
|
<td><a name="uuidSequence"/>log4j2.uuidSequence
|
|
<br />
|
|
diff --git a/src/site/xdoc/manual/extending.xml b/src/site/xdoc/manual/extending.xml
|
|
index ba04d68..04c742a 100644
|
|
--- a/src/site/xdoc/manual/extending.xml
|
|
+++ b/src/site/xdoc/manual/extending.xml
|
|
@@ -92,7 +92,10 @@
|
|
<dd>Associates LoggerContexts with the ClassLoader that created the caller of the getLogger call. This is
|
|
the default ContextSelector.</dd>
|
|
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html">JndiContextSelector</a></dt>
|
|
- <dd>Locates the LoggerContext by querying JNDI.</dd>
|
|
+ <dd>Locates the LoggerContext by querying JNDI. Please see <a href="../manual/configuration.html#allowedJndiProtocols">log4j2.allowedJndiProtocols</a>,
|
|
+ <a href="../manual/configuration.html#allowedLdapClasses">log4j2.allowedLdapClasses</a>, and
|
|
+ <a href="../manual/configuration.html#allowedLdapHosts">log4j2.allowedLdapHosts</a> for restrictions on using JNDI
|
|
+ with Log4j.</dd>
|
|
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html">AsyncLoggerContextSelector</a></dt>
|
|
<dd>Creates a LoggerContext that ensures that all loggers are AsyncLoggers.</dd>
|
|
<dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html">BundleContextSelector</a></dt>
|
|
diff --git a/src/site/xdoc/manual/lookups.xml b/src/site/xdoc/manual/lookups.xml
|
|
index d699e78..cc6a66f 100644
|
|
--- a/src/site/xdoc/manual/lookups.xml
|
|
+++ b/src/site/xdoc/manual/lookups.xml
|
|
@@ -270,6 +270,13 @@
|
|
The JndiLookup allows variables to be retrieved via JNDI. By default the key will be prefixed with
|
|
java:comp/env/, however if the key contains a ":" no prefix will be added.
|
|
</p>
|
|
+ <p>By default the JDNI Lookup only supports the java, ldap, and ldaps protocols or no protocol. Additional
|
|
+ protocols may be supported by specifying them on the <code>log4j2.allowedJndiProtocols</code> property.
|
|
+ When using LDAP Java classes that implement the Referenceable interface are not supported for security
|
|
+ reasons. Only the Java primative classes are supported by default as well as any classes specified by the
|
|
+ <code>log4j2.allowedLdapClasses</code> property. When using LDAP only references to the local host name
|
|
+ or ip address are supported along with any hosts or ip addresses listed in the
|
|
+ <code>log4j2.allowedLdapHosts</code> property.</p>
|
|
<pre class="prettyprint linenums"><![CDATA[
|
|
<File name="Application" fileName="application.log">
|
|
<PatternLayout>
|
|
--
|
|
2.27.0
|
|
|