3

In order to disable insecure http methods, I have used a request filter

@Component
public class MethodFilter extends OncePerRequestFilter {

    private final String[] allowedMethods = new String[]{"PUT", "POST", "GET", "OPTIONS"};

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        if (Arrays.stream(allowedMethods).noneMatch(x -> x.equals(request.getMethod()))) {
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
        filterChain.doFilter(request, response);
    }
}

This works perfectly for all methods except "TRACE". For trace method, this filter is not invoked and I get a echo back of the all the headers in response body

TRACE /error HTTP/1.1
my-header: test
accept: */*
host: localhost:8087
accept-encoding: gzip, deflate, br
connection: keep-alive

For all other methods which are not in the list I get result as expected

{
    "timestamp": "2021-11-03T11:49:48.545+0000",
    "status": 405,
    "error": "Method Not Allowed",
    "message": "DELETE method is not allowed",
    "path": "/test"
}

Referring to doc it seems, trace requests are sent to frameworkservlet and processed there itself. Have tried setting spring.mvc.dispatch-trace-request=true but now the responses are clubbed like this (filter still not invoked)

{
    "timestamp": "2021-11-03T11:49:48.545+0000",
    "status": 405,
    "error": "Method Not Allowed",
    "message": "TRACE method is not allowed",
    "path": "/test"
}TRACE /error HTTP/1.1
my-header: test
accept: */*
host: localhost:8087
accept-encoding: gzip, deflate, br
connection: keep-alive

My question is how can I make TRACE response as same as the other requests ?

Note: The solution in this thread did not work for me.

Edit: Found the solution. An interceptor does the trick instead of a filter

@Component
public class MethodInterceptor implements HandlerInterceptor {

    private final String[] allowedMethods = new String[]{"PUT", "POST", "GET", "OPTIONS"};

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (Arrays.stream(allowedMethods).noneMatch(x -> x.equals(request.getMethod()))) {
            response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
            response.setHeader("Allow", "PUT, POST, GET, OPTIONS");
            response.setContentType("message/http");
            response.getWriter().println(request.getMethod() + " method not allowed");
            response.getWriter().flush();
            return false;
        }
        return true;
    }
}

And add the interceptor via config file

    @Configuration
    public class InterceptorConfiguration implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MethodInterceptor());
        }
    }

This needs to be used in conjunction with spring.mvc.dispatch-trace-request=true

SpartanX1
  • 201
  • 2
  • 8

2 Answers2

2

What if you try configuring Spring Security for it ... The approach with writing the filter manually, it feels a bit low level ...

@Override
protected void configure(HttpSecurity http) throws Exception
{
     http
    .authorizeRequests()
       // You can actually disable other methods here as well
      .antMatchers(HttpMethod.TRACE,"/**").denyAll()
    .httpBasic();
}

If this does not work for you ... according to the docs it says

Note that HttpServlets default TRACE processing will be applied
in any case if your controllers happen to not generate a response
of content type 'message/http' (as required for a TRACE response)

Why don't you try setting content type header to message/http when responding to a TRACE request in your filter ?

Another option is disabling this in the dispatcher servlet

Arthur Klezovich
  • 2,595
  • 1
  • 13
  • 17
0

TRACE is currently disallowed by default, at least in Spring-Boot 3.1, since the default firewall WebSecurity uses StrictFirewall, which has as allowed methods DELETE, GET, HEAD, OPTIONS, PATCH, POST and PUT (https://github.com/spring-projects/spring-security/blob/492bde7808462dac36b399531f45a297bc212d69/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java#L562)

This can be tuned easily with:

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    StrictHttpFirewall strictHttpFirewall = new StrictHttpFirewall();
    strictHttpFirewall.setAllowedHttpMethods(List.of(HttpMethod.GET.name(), HttpMethod.POST.name()))
    return (web) -> web.httpFirewall(strictHttpFirewall);
}    

Whimusical
  • 6,401
  • 11
  • 62
  • 105