Uniform handling of `URLConnection`
The two versions of the UrlConnectionFactory.createConnection method currently handle URLs differently, leading to inconsistencies:
-
Protocol Enforcement:
- The four-parameter version enforces the
log4j2.configurationAllowedProtocolsfor all protocols. - The one-parameter version enforces it only for
httpandhttps.
- The four-parameter version enforces the
-
Caching Behavior for the
jarProtocol:- The four-parameter version disables caching for the
jarprotocol unconditionally, regardless of theURLConnectionused. - The one-parameter version only disables caching for
JarURLConnectionand its subclasses. - This discrepancy is related to the issue reported in LOG4J2-3663.
- The four-parameter version disables caching for the
Before implementing any changes, we need to clarify the intended purpose of the log4j2.configurationAllowedProtocols configuration property:
-
Purpose of the Property:
- The exception message "No external protocols have been enabled," which occurs when the property is set to
_none, suggests that this property is intended to control which external protocols can be used to retrieve configuration files outside the Java application. This likely excludes internal resources like classpath-based files.
- The exception message "No external protocols have been enabled," which occurs when the property is set to
-
Handling of
fileandclasspath:- The
fileprotocol is typically handled by theFileAPI and cannot be disabled through this configuration property. - The informal
classpathprotocol, while internal, is converted to aURLviaClassLoader.getResource, which treats it as an external resource. This does not trigger thelog4j2.configurationAllowedProtocolscheck, since it uses the one-parameterUrlConnectionFactory.createConnectionmethod.
- The
-
Spring Boot's Handling of
classpath:- Spring Boot similarly converts the
classpathprotocol to aURL. However, it uses the four-parameterUrlConnectionFactory.createConnectionmethod, which inadvertently applies thelog4j2.configurationAllowedProtocolscheck, despite theclasspathprotocol being internal.
- Spring Boot similarly converts the
@rgoers, @vy, what do you think? How should we solve the current inconsistencies of log4j2.configurationAllowedProtocols?
Note: We should also improve the handling of jar URLs to prevent the retrieval of untrusted files through jar:http:.
@ppkarwasz, agreed that log4j2.configurationAllowedProtocols was probably intended only for external protocols – i.e., neither file, nor classpath. The title of the ticket delivered this feature hints in this direction too: LOG4J2-3297: Disable remote loading of log4j configuration to prevent MiTM Attacks. That said,
- non-external protocols are valid URL protocols too, and hence, should be subject to same regulations.
UrlConnectionFactory.DEFAULT_ALLOWED_PROTOCOLSis set to"https, file, jar", which is a mix of both external and internal protocols.
I suggest the following
- Make it clear that
log4j2.configurationAllowedProtocolsis exercised for all configuration locations - Match the implementations to do so: fix the inconsistencies across
createConnection() - Extend
DEFAULT_ALLOWED_PROTOCOLSwithclasspath
I believe the classpath pseudo-protocol should be handled differently due to its unique nature. A classpath URL doesn't directly correspond to a single protocol; instead, it resolves to various underlying protocols, such as jar:file, war:file, or even war:jar:file. However, requiring users to explicitly add all these protocols (e.g., jar, file, war) to log4j2.configurationAllowedProtocols would be cumbersome for users.
requiring users to explicitly add all these protocols (e.g.,
jar,file,war) tolog4j2.configurationAllowedProtocolswould be cumbersome for users.
I think the mechanism should be well-sealed (allow these protocols and only these!) with good defaults. I don't think it'd be too much to expect from those deviating from the defaults to know what they are doing.
I don't think it'd be too much to expect from those deviating from the defaults to know what they are doing.
That’s fair in principle — but in practice, users often don’t fully understand how classpath: URLs are resolved. As an example, I wasn’t aware myself that under GraalVM, classpath: expands to a resource: URL.
The behavior of classpath: can vary across environments — especially on different application servers — which can lead to subtle, hard-to-diagnose issues. This variability is exactly why it makes sense to handle classpath: as a special case.