Browse Source

ZOOKEEPER-3772: JettyAdminServer should not allow Http TRACE method

A nessus scan pinged the cluster after I upgrade my zookeeper cluster, because the 8080 port of JettyAdminServer allows Http TRACE method.

Author: lingjinjiang <lingjinjiang@gmail.com>

Reviewers: Mate Szalay-Beko <symat@apache.org>, Andor Molnar <andor@apache.org>, Norbert Kalmar <nkalmar@apache.org>

Closes #1296 from lingjinjiang/master
lingjinjiang 5 years ago
parent
commit
44de549657

+ 22 - 0
zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/JettyAdminServer.java

@@ -34,6 +34,8 @@ import org.apache.zookeeper.common.QuorumX509Util;
 import org.apache.zookeeper.common.X509Util;
 import org.apache.zookeeper.server.ZooKeeperServer;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.SecureRequestCustomizer;
@@ -41,6 +43,7 @@ import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -153,6 +156,7 @@ public class JettyAdminServer implements AdminServer {
 
         ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
         context.setContextPath("/*");
+        constrainTraceMethod(context);
         server.setHandler(context);
 
         context.addServlet(new ServletHolder(new CommandServlet()), commandUrl + "/*");
@@ -266,4 +270,22 @@ public class JettyAdminServer implements AdminServer {
         return links;
     }
 
+    /**
+     * Add constraint to a given context to disallow TRACE method
+     * @param ctxHandler the context to modify
+     */
+    private void constrainTraceMethod(ServletContextHandler ctxHandler) {
+        Constraint c = new Constraint();
+        c.setAuthenticate(true);
+
+        ConstraintMapping cmt = new ConstraintMapping();
+        cmt.setConstraint(c);
+        cmt.setMethod("TRACE");
+        cmt.setPathSpec("/*");
+
+        ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
+        securityHandler.setConstraintMappings(new ConstraintMapping[] {cmt});
+
+        ctxHandler.setSecurityHandler(securityHandler);
+    }
 }

+ 20 - 0
zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/JettyAdminServerTest.java

@@ -18,11 +18,13 @@
 
 package org.apache.zookeeper.server.admin;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
 import java.net.URL;
 import java.security.GeneralSecurityException;
 import java.security.Security;
@@ -152,6 +154,7 @@ public class JettyAdminServerTest extends ZKTestCase {
         try {
             server.start();
             queryAdminServer(jettyAdminPort);
+            traceAdminServer(jettyAdminPort);
         } finally {
             server.shutdown();
         }
@@ -262,4 +265,21 @@ public class JettyAdminServerTest extends ZKTestCase {
         assertTrue(line.length() > 0);
     }
 
+    /**
+     * Using TRACE method to visit admin server
+     */
+    private void traceAdminServer(int port) throws IOException {
+      traceAdminServer(String.format(URL_FORMAT, port));
+      traceAdminServer(String.format(HTTPS_URL_FORMAT, port));
+    }
+
+    /**
+     * Using TRACE method to visit admin server, the response should be 403 forbidden
+     */
+    private void traceAdminServer(String urlStr) throws IOException {
+        HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection();
+        conn.setRequestMethod("TRACE");
+        conn.connect();
+        assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode());
+    }
 }