-
Notifications
You must be signed in to change notification settings - Fork 41.4k
Description
Tomcat by default disables TRACE request. Each TRACE reqeust retrives response like below:
HTTP/1.1 405
Allow: HEAD, GET, OPTIONS
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 735
Date: Thu, 22 Dec 2022 22:22:22 GMT
<!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 405 – Method Not Allowed</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> TRACE method is not allowed</p><p><b>Description</b> The method received in the request-line is known by the origin server but not supported by the target resource.</p><hr class="line" /><h3>Apache Tomcat/10.0.27</h3></body></html>
Spring Boot follows the similar behaviour by responding 405 (Method Not Allowed). However, although response status code is set to 405, Spring Boot still outputs request headers in the body:
HTTP/1.1 405
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT
Content-Type: message/http
Content-Length: 273
Date: Thu, 22 Dec 2022 22:22:22 GMT
TRACE /error HTTP/1.1
host: localhost:8080
user-agent: curl/7.87.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.5
IMO it is wrong behavior. If it's not, then we need an option to disable/forbid TRACE completely.
Below is my thoughts on this issue.
By default, allowTrace
attribute of Tomcat connector is set as false. This causes TRACE request forwarded to error page. In vanilla Spring Boot application, there is a BasicErrorController
, by which the TRACE request is handled. We know that DispatcherServlet
accepts and handles all requests, so if we take a look into implementation details of doTrace
(Inherited from FrameworkServlet
), we can easily figure it out why request headers are printed.
@Override
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (this.dispatchTraceRequest) {
processRequest(request, response);
if ("message/http".equals(response.getContentType())) {
// Proper TRACE response coming from a handler - we're done.
return;
}
}
super.doTrace(request, response);
}
By default, spring.mvc.dispatch-trace-request
is set to false, therefore this.processRequest
is bypassed and super.doTrace
is called. In this context, HttpServlet.doTrace
is called, by which request headers are printed.
What problem there is here is that FrameworkServlet.doTrace
enforces corresponding handler to construct response in content type of message/http
, but BasicErrorController
does not handle TRACE request specifically.
Currently I find two ways to disable TRACE request completely.
One workaround is to disable ErrorMvcAutoConfiguration
. When ErrorMvcAutoConfiguration
is execluded on startup, Spring Boot will respond like below:
HTTP/1.1 405
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 449
Date: Thu, 22 Dec 2022 22:22:22 GMT
<!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 405 – Method Not Allowed</h1></body></html>
The other workaround is to enable spring.mvc.dispatch-trace-request
and implements my own ErrorController
which handles requests case by case.
However, neither of them is concise and good enough. The former cuts off global error handling at the same time, and the latter is also restricted to construct message/http
compatible response, and may expose unexpected TRACE endpoints.
Furthermore to say, I think we need a mechanism to whitelist error handler and avoid it being handled by FrameworkServlet.doTrace
, or least add an option to allow us to bypass message/http
requirement for TRACE request, giving us maximum freedom to customize TRACE response.