This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch activemq-6.2.x
in repository https://gitbox.apache.org/repos/asf/activemq.git
The following commit(s) were added to refs/heads/activemq-6.2.x by this push:
new be8415f248 [6.2.x] Harden web console and Jolokia access by default
(#2025) (#2037)
be8415f248 is described below
commit be8415f248d311188a37d5e51b508acc80a0fb2d
Author: JB Onofré <[email protected]>
AuthorDate: Sat May 23 06:33:01 2026 +0200
[6.2.x] Harden web console and Jolokia access by default (#2025) (#2037)
* Harden web console and Jolokia access by default
jetty.xml:
- Add Referrer-Policy and Permissions-Policy response headers; provide
commented-out Strict-Transport-Security for HTTPS deployments.
- Wrap the existing HandlerCollection in an InetAccessHandler and restrict
access to loopback (127.0.0.1, ::1) by default. Provide commented-out
templates for RFC1918 includes and exclude rules.
- Tie Server.start() to the loopback include beans via depends-on so the
allow-list is fully populated before the server starts.
- Add a commented-out ForwardedRequestCustomizer for reverse-proxy setups,
with a warning about header spoofing when the proxy does not strip
inbound X-Forwarded-* headers.
jolokia-access.xml:
- Restrict Jolokia to HTTP POST to kill GET-based CSRF/SSRF vectors.
- Deny destructive and privileged broker operations (terminateJVM, stop,
restart, add/removeConnector, add/removeQueue/Topic, durable subscriber
lifecycle, runtime limit setters, reloadLog4jProperties).
- Deny destination message-data mutation (purge, remove/copy/move
messages, sendTextMessage*, pause/resume); browse* remains allowed.
- Deny durable subscriber destroy/setSelector and JobScheduler removeJob*.
- Deny NetworkConnector Password/RemotePassword attributes and credential
setters.
- Deny known JMX RCE / introspection surfaces: javax.management.loading
MLet, JMImplementation, java.util.logging, java.lang:type=Memory and
ClassLoading, plus java.lang:type=Runtime SystemProperties and
InputArguments.
* jetty.xml: restrict Jolokia endpoint to admins role
Add a jolokiaSecurityConstraintMapping that binds adminSecurityConstraint
(admins-only) to /api/jolokia/*, mirroring how *.action is gated on the
web console. Wired into securityHandler before securityConstraintMapping
so the admin role check applies to all Jolokia requests rather than the
broader users/admins constraint.
---
assembly/src/release/conf/jetty.xml | 139 +++++++++++++++++++++++---
assembly/src/release/conf/jolokia-access.xml | 141 ++++++++++++++++++++++++++-
2 files changed, 266 insertions(+), 14 deletions(-)
diff --git a/assembly/src/release/conf/jetty.xml
b/assembly/src/release/conf/jetty.xml
index f1142cba7e..a2799b6297 100644
--- a/assembly/src/release/conf/jetty.xml
+++ b/assembly/src/release/conf/jetty.xml
@@ -23,6 +23,31 @@
<property name="sendServerVersion" value="false"/>
<property name="sendXPoweredBy" value="false"/>
<property name="sendDateHeader" value="false"/>
+ <!--
+ When the web console sits behind a reverse proxy or load balancer,
+ uncomment the customizer below so Jetty honors X-Forwarded-* (or
+ RFC 7239 Forwarded) headers when populating
request.getRemoteAddr(),
+ request.getScheme(), etc. This is what gets the real client IP into
+ access logs and audit trails.
+
+ WARNING: ForwardedRequestCustomizer trusts these headers from any
+ client. Only enable it when the upstream proxy strips inbound
+ X-Forwarded-* headers, otherwise a remote client can spoof its
+ source IP and apparent scheme.
+
+ Note: this does NOT change InetAccessHandler's filtering — that
+ handler always evaluates the socket peer (the proxy itself) and
+ ignores forwarded headers. In a proxied deployment either keep the
+ allow list scoped to the proxy address and rely on the proxy for
+ client-IP filtering, or remove InetAccessHandler entirely.
+ -->
+ <!--
+ <property name="customizers">
+ <list>
+ <bean
class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/>
+ </list>
+ </property>
+ -->
</bean>
<bean id="jaasLoginService"
class="org.eclipse.jetty.jaas.JAASLoginService">
@@ -57,6 +82,10 @@
<property name="constraint" ref="adminSecurityConstraint" />
<property name="pathSpec" value="*.action" />
</bean>
+ <bean id="jolokiaSecurityConstraintMapping"
class="org.eclipse.jetty.security.ConstraintMapping">
+ <property name="constraint" ref="adminSecurityConstraint" />
+ <property name="pathSpec" value="/api/jolokia/*" />
+ </bean>
<bean id="rewriteHandler"
class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
<property name="rules">
@@ -112,6 +141,14 @@
<property name="name" value="Content-Security-Policy"/>
<property name="value" value="style-src-elem 'self'
'unsafe-inline'; style-src 'self'; img-src 'self' data:; script-src-elem
'self'; default-src 'none'; object-src 'none'; frame-ancestors 'none'; base-uri
'none';" />
</bean>
+ <!-- Uncomment when serving the console over HTTPS only -->
+ <!--
+ <bean id="header"
class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+ <property name="pattern" value="*"/>
+ <property name="name" value="Strict-Transport-Security"/>
+ <property name="value" value="max-age=31536000;
includeSubDomains"/>
+ </bean>
+ -->
</list>
</property>
</bean>
@@ -154,6 +191,7 @@
<property name="constraintMappings">
<list>
<ref bean="adminSecurityConstraintMapping" />
+ <ref bean="jolokiaSecurityConstraintMapping" />
<ref bean="securityConstraintMapping" />
</list>
</property>
@@ -169,19 +207,94 @@
<property name="port" value="8161"/>
</bean>
+ <bean id="handlers"
class="org.eclipse.jetty.server.handler.HandlerCollection">
+ <property name="handlers">
+ <list>
+ <ref bean="contexts" />
+ <ref bean="securityHandler" />
+ </list>
+ </property>
+ </bean>
+
+ <!--
+ IP-based access control for the web console.
+ Patterns accept: exact IP (192.168.1.1), CIDR (10.0.0.0/8),
+ range (10.0.0.0-10.255.255.255), or qualified with path/connector
+ using '|' (e.g. 192.168.1.0/24|/api).
+ Exclude rules take precedence over include rules.
+ With the default host binding of 127.0.0.1, only localhost is
reachable;
+ if the bind address is broadened (e.g. 0.0.0.0), add explicit include
+ entries below for the networks that should reach the console.
+ -->
+ <bean id="inetAccessHandler"
class="org.eclipse.jetty.server.handler.InetAccessHandler">
+ <property name="handler" ref="handlers"/>
+ </bean>
+
+ <!-- Allowed clients (include rules) -->
+ <bean id="inetAccessIncludeLoopbackV4"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="include"/>
+ <property name="arguments">
+ <list><value>127.0.0.1</value></list>
+ </property>
+ </bean>
+ <bean id="inetAccessIncludeLoopbackV6"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="inetAccessIncludeLoopbackV4">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="include"/>
+ <property name="arguments">
+ <list><value>::1</value></list>
+ </property>
+ </bean>
+ <!--
+ Example: allow standard private network ranges. Copy a block and
+ chain depends-on to enforce ordering on container startup.
+
+ <bean id="inetAccessIncludeRfc1918Class10"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="inetAccessIncludeLoopbackV6">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="include"/>
+ <property name="arguments">
+ <list><value>10.0.0.0/8</value></list>
+ </property>
+ </bean>
+ <bean id="inetAccessIncludeRfc1918Class172"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="inetAccessIncludeRfc1918Class10">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="include"/>
+ <property name="arguments">
+ <list><value>172.16.0.0/12</value></list>
+ </property>
+ </bean>
+ <bean id="inetAccessIncludeRfc1918Class192"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="inetAccessIncludeRfc1918Class172">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="include"/>
+ <property name="arguments">
+ <list><value>192.168.0.0/16</value></list>
+ </property>
+ </bean>
+ -->
+
+ <!--
+ Denied clients (exclude rules). Exclude rules take precedence over
+ include rules. Empty by default; add entries below to block specific
+ addresses or networks.
+
+ <bean id="inetAccessExcludeExample"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="inetAccessIncludeLoopbackV6">
+ <property name="targetObject" ref="inetAccessHandler"/>
+ <property name="targetMethod" value="exclude"/>
+ <property name="arguments">
+ <list><value>1.2.3.4</value></list>
+ </property>
+ </bean>
+ -->
+
<bean id="Server" depends-on="jettyPort"
class="org.eclipse.jetty.server.Server"
destroy-method="stop">
- <property name="handler">
- <bean id="handlers"
class="org.eclipse.jetty.server.handler.HandlerCollection">
- <property name="handlers">
- <list>
- <ref bean="contexts" />
- <ref bean="securityHandler" />
- </list>
- </property>
- </bean>
- </property>
+ <property name="handler" ref="inetAccessHandler"/>
</bean>
@@ -230,10 +343,10 @@
</property>
</bean>
- <bean id="invokeStart"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
- depends-on="broker, configureJetty, invokeConnectors">
+ <bean id="invokeStart"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
+ depends-on="broker, configureJetty, invokeConnectors,
inetAccessIncludeLoopbackV6">
<property name="targetObject" ref="Server" />
- <property name="targetMethod" value="start" />
+ <property name="targetMethod" value="start" />
</bean>
diff --git a/assembly/src/release/conf/jolokia-access.xml
b/assembly/src/release/conf/jolokia-access.xml
index 97b099a5b7..6844c31460 100644
--- a/assembly/src/release/conf/jolokia-access.xml
+++ b/assembly/src/release/conf/jolokia-access.xml
@@ -17,7 +17,14 @@
-->
<restrict>
- <!-- Enforce that an Origin/Referer header is present to prevent CSRF -->
+ <!-- Restrict HTTP methods to POST only (mitigates GET-based CSRF/SSRF
vectors) -->
+ <http>
+ <method>post</method>
+ </http>
+
+ <!-- Enforce that an Origin/Referer header is present to prevent CSRF.
+ Add explicit <allow-origin> entries below if the console is served from
+ a different host. -->
<cors>
<strict-checking/>
</cors>
@@ -46,11 +53,143 @@
<!-- deny all operations or getting attributes from these mbeans -->
<deny>
+ <!-- ActiveMQ broker: deny destructive / privileged operations.
+ Safe read-only getters, browse*, and statistics queries remain allowed
+ via the org.apache.activemq:* entry in <allow> above. -->
+ <mbean>
+ <name>org.apache.activemq:type=Broker,brokerName=*</name>
+ <!-- JVM and broker lifecycle -->
+ <operation>terminateJVM</operation>
+ <operation>stop</operation>
+ <operation>stopGracefully</operation>
+ <operation>restart</operation>
+ <operation>gc</operation>
+ <!-- Topology and destination management -->
+ <operation>addConnector</operation>
+ <operation>removeConnector</operation>
+ <operation>addNetworkConnector</operation>
+ <operation>removeNetworkConnector</operation>
+ <operation>addQueue</operation>
+ <operation>removeQueue</operation>
+ <operation>addTopic</operation>
+ <operation>removeTopic</operation>
+ <operation>createDurableSubscriber</operation>
+ <operation>destroyDurableSubscriber</operation>
+ <!-- Runtime configuration mutation -->
+ <operation>reloadLog4jProperties</operation>
+ <operation>setMemoryLimit</operation>
+ <operation>setStoreLimit</operation>
+ <operation>setTempLimit</operation>
+ <operation>setJobSchedulerStoreLimit</operation>
+ <operation>setMaxUncommittedCount</operation>
+ </mbean>
+
+ <!-- Destinations: deny message data manipulation and injection.
+ browse / browseAsTable / counters remain allowed. -->
+ <mbean>
+
<name>org.apache.activemq:type=Broker,brokerName=*,destinationType=*,destinationName=*</name>
+ <operation>purge</operation>
+ <operation>removeMessage</operation>
+ <operation>removeMatchingMessages</operation>
+ <operation>copyMessageTo</operation>
+ <operation>copyMatchingMessagesTo</operation>
+ <operation>moveMessageTo</operation>
+ <operation>moveMatchingMessagesTo</operation>
+ <operation>retryMessage</operation>
+ <operation>retryMessages</operation>
+ <operation>removeMessageGroup</operation>
+ <operation>removeAllMessageGroups</operation>
+ <operation>sendTextMessage</operation>
+ <operation>sendTextMessageWithProperties</operation>
+ <operation>pause</operation>
+ <operation>resume</operation>
+ </mbean>
+
+ <!-- Durable subscriptions: deny destroy and selector tampering -->
+ <mbean>
+
<name>org.apache.activemq:type=Broker,brokerName=*,destinationType=*,destinationName=*,endpoint=Consumer,clientId=*,consumerId=*</name>
+ <operation>destroy</operation>
+ <operation>removeMessage</operation>
+ <operation>setSelector</operation>
+ </mbean>
+
+ <!-- JobScheduler: deny job removal -->
+ <mbean>
+
<name>org.apache.activemq:type=Broker,brokerName=*,service=JobScheduler,name=*</name>
+ <operation>removeJob</operation>
+ <operation>removeAllJobs</operation>
+ <operation>removeAllJobsAtScheduledTime</operation>
+ </mbean>
+
+ <!-- Log4JConfiguration MBean: deny runtime log level / config changes -->
+ <mbean>
+
<name>org.apache.activemq:type=Broker,brokerName=*,service=Log4JConfiguration</name>
+ <operation>setRootLogLevel</operation>
+ <operation>setLogLevel</operation>
+ <operation>reloadLog4jProperties</operation>
+ </mbean>
+
+ <!-- NetworkConnector: deny credential exposure and config mutation -->
+ <mbean>
+
<name>org.apache.activemq:type=Broker,brokerName=*,connector=networkConnectors,networkConnectorName=*</name>
+ <attribute>Password</attribute>
+ <attribute>RemotePassword</attribute>
+ <operation>setUserName</operation>
+ <operation>setPassword</operation>
+ <operation>setRemoteUserName</operation>
+ <operation>setRemotePassword</operation>
+ <operation>setBridgeTempDestinations</operation>
+ <operation>setConduitSubscriptions</operation>
+ <operation>setDispatchAsync</operation>
+ <operation>setDynamicOnly</operation>
+ <operation>setMessageTTL</operation>
+ <operation>setConsumerTTL</operation>
+ <operation>setPrefetchSize</operation>
+ <operation>setAdvisoryPrefetchSize</operation>
+ <operation>setDecreaseNetworkConsumerPriority</operation>
+ <operation>setSuppressDuplicateQueueSubscriptions</operation>
+ <operation>setSuppressDuplicateTopicSubscriptions</operation>
+ </mbean>
+
+ <!-- MLet allows remote class loading: well-known JMX/Jolokia RCE vector
-->
+ <mbean>
+ <name>javax.management.loading:type=MLet</name>
+ <attribute>*</attribute>
+ <operation>*</operation>
+ </mbean>
+ <mbean>
+ <name>JMImplementation:*</name>
+ <attribute>*</attribute>
+ <operation>*</operation>
+ </mbean>
<mbean>
<name>org.apache.logging.log4j2:*</name>
<attribute>*</attribute>
<operation>*</operation>
</mbean>
+ <mbean>
+ <name>java.util.logging:*</name>
+ <attribute>*</attribute>
+ <operation>*</operation>
+ </mbean>
+ <!-- Forces GC, toggles verbose, etc. -->
+ <mbean>
+ <name>java.lang:type=Memory</name>
+ <attribute>*</attribute>
+ <operation>*</operation>
+ </mbean>
+ <mbean>
+ <name>java.lang:type=ClassLoading</name>
+ <attribute>*</attribute>
+ <operation>*</operation>
+ </mbean>
+ <!-- Exposes system properties and JVM input arguments -->
+ <mbean>
+ <name>java.lang:type=Runtime</name>
+ <attribute>SystemProperties</attribute>
+ <attribute>InputArguments</attribute>
+ <operation>*</operation>
+ </mbean>
<mbean>
<name>com.sun.management:type=DiagnosticCommand</name>
<attribute>*</attribute>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact