This is an automated email from the ASF dual-hosted git repository.

jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq.git


The following commit(s) were added to refs/heads/main by this push:
     new 052369f00a Harden web console and Jolokia access by default (#2025)
052369f00a is described below

commit 052369f00a43757e3694abbbe6d0c1a8e72fa4d5
Author: JB Onofré <[email protected]>
AuthorDate: Fri May 22 05:47:40 2026 +0200

    Harden web console and Jolokia access by default (#2025)
    
    * 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          | 149 ++++++++++++++++++++++++---
 assembly/src/release/conf/jolokia-access.xml | 141 ++++++++++++++++++++++++-
 2 files changed, 276 insertions(+), 14 deletions(-)

diff --git a/assembly/src/release/conf/jetty.xml 
b/assembly/src/release/conf/jetty.xml
index fd000137fc..c32f0ac02c 100644
--- a/assembly/src/release/conf/jetty.xml
+++ b/assembly/src/release/conf/jetty.xml
@@ -21,6 +21,31 @@
 
     <bean id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
         <property name="sendServerVersion" 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">
@@ -55,6 +80,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">
@@ -90,6 +119,24 @@
                     <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>
+                <bean id="header" 
class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+                    <property name="pattern" value="*"/>
+                    <property name="name" value="Referrer-Policy"/>
+                    <property name="value" value="no-referrer"/>
+                </bean>
+                <bean id="header" 
class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+                    <property name="pattern" value="*"/>
+                    <property name="name" value="Permissions-Policy"/>
+                    <property name="value" value="accelerometer=(), camera=(), 
geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), 
usb=()"/>
+                </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>
@@ -132,6 +179,7 @@
         <property name="constraintMappings">
             <list>
                 <ref bean="adminSecurityConstraintMapping" />
+                <ref bean="jolokiaSecurityConstraintMapping" />
                 <ref bean="securityConstraintMapping" />
             </list>
         </property>
@@ -147,19 +195,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>
 
@@ -208,10 +331,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


Reply via email to