Java embedded jetty is accepting HTTP TRACE method

六月ゝ 毕业季﹏ 提交于 2019-12-04 10:59:56
Jan

On your Constraint object, you need to call setAuthenticate(true), and ensure that you don't call setRoles(String[]). This makes it the equivalent of a <security-constraint> with an empty <auth-constraint>, which forbids access.

The reason it works with the DefaultServlet and not the CXFServlet is because the DefaultServlet specifically denies access to the TRACE method.

Extending the Server class and overriding the handle() method worked best for me.

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;

public class MyServer extends Server {

    @Override
    public void handle(HttpChannel<?> connection) throws IOException, ServletException {
        Request request=connection.getRequest();
        Response response=connection.getResponse();

        if ("TRACE".equals(request.getMethod())){
            request.setHandled(true);
            response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        } else {
            super.handle(connection);
        }
    }
}

Jan's answer works (of course). However, it will cause jetty to print a warning on startup.

WARNING ... SecurityHandler ... has uncovered http methods for path ...

To avoid this first add the constraint as in Jan's answer (disable TRACE) and then add another constraint (allow everything but TRACE). I invoke the following code for each ServletContextHandler:

private void disableTraceMethodForHandler(final ServletContextHandler servletContextHandler) {
    SecurityHandler securityHandler = servletContextHandler.getSecurityHandler();
    if (securityHandler == null) {
        securityHandler = new ConstraintSecurityHandler();
        servletContextHandler.setSecurityHandler(securityHandler);
    }
    if (securityHandler instanceof ConstraintSecurityHandler) {
        ConstraintSecurityHandler constraintSecurityHandler = (ConstraintSecurityHandler) securityHandler;

        ConstraintMapping disableTraceMapping = new ConstraintMapping();
        Constraint disableTraceConstraint = new Constraint();
        disableTraceConstraint.setName("Disable TRACE");
        disableTraceConstraint.setAuthenticate(true);
        disableTraceMapping.setConstraint(disableTraceConstraint);
        disableTraceMapping.setPathSpec("/");
        disableTraceMapping.setMethod("TRACE");
        constraintSecurityHandler.addConstraintMapping(disableTraceMapping);

        ConstraintMapping enableEverythingButTraceMapping = new ConstraintMapping();
        Constraint enableEverythingButTraceConstraint = new Constraint();
        enableEverythingButTraceConstraint.setName("Enable everything but TRACE");
        enableEverythingButTraceMapping.setConstraint(enableEverythingButTraceConstraint);
        enableEverythingButTraceMapping.setMethodOmissions(new String[] {"TRACE"});
        enableEverythingButTraceMapping.setPathSpec("/");
        constraintSecurityHandler.addConstraintMapping(enableEverythingButTraceMapping);
    }
}

I figured out this solution after I found this issue in Google's appengine-java-vm-runtime and the fix, both by Jan. The code above should do the same as the XML config there.

You can create a filter:

...
@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        if ("TRACE".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
            return;
        }
        chain.doFilter(request, response);
    }
....

Your code works as-is.

package jetty;

import java.io.File;
import java.nio.file.Path;

import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;

public class BanTraceExample
{
    private static final Logger LOG = Log.getLogger(BanTraceExample.class);

    public static void main(String[] args)
    {
        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(9090);
        server.addConnector(connector);

        Path basePath = new File(System.getProperty("test.base",System.getProperty("user.dir"))).toPath().toAbsolutePath();
        LOG.info("Base Directory: {}",basePath);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS | ServletContextHandler.SECURITY);
        context.setContextPath("/");
        server.setHandler(context);

        Constraint constraint = new Constraint();
        constraint.setName("Disable TRACE");

        ConstraintMapping mapping = new ConstraintMapping();
        mapping.setConstraint(constraint);
        mapping.setMethod("TRACE");
        mapping.setPathSpec("/");

        ConstraintSecurityHandler securityHandler = (ConstraintSecurityHandler)context.getSecurityHandler();
        securityHandler.addConstraintMapping(mapping);

        ServletHolder holderDef = new ServletHolder("test",DefaultServlet.class);
        holderDef.setInitParameter("resourceBase",basePath.toString());
        holderDef.setInitParameter("dirAllowed","true");
        context.addServlet(holderDef,"/");

        try
        {
            server.start();
            server.join();
        }
        catch (Throwable t)
        {
            t.printStackTrace(System.err);
        }
    }
}

The test.

Normal GET request:

$ curl http://127.0.0.1:9090/.gitignore
.classpath
.project
.settings
target/
*.swp
*.log
*~

TRACE Request:

$ curl -v -X TRACE http://127.0.0.1:9090/.gitignore
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 9090 (#0)
> TRACE /.gitignore HTTP/1.1
> User-Agent: curl/7.40.0
> Host: 127.0.0.1:9090
> Accept: */*
>
< HTTP/1.1 405 Method Not Allowed
< Date: Mon, 30 Mar 2015 21:48:53 GMT
< Cache-Control: must-revalidate,no-cache,no-store
< Content-Type: text/html; charset=ISO-8859-1
< Content-Length: 297
< Server: Jetty(9.2.10.v20150310)
<
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 405 </title>
</head>
<body>
<h2>HTTP ERROR: 405</h2>
<p>Problem accessing /.gitignore. Reason:
<pre>    Method Not Allowed</pre></p>
<hr /><i><small>Powered by Jetty://</small></i>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!