禁用Tomcat中所有默认的HTTP错误响应内容

Posted

技术标签:

【中文标题】禁用Tomcat中所有默认的HTTP错误响应内容【英文标题】:Disable all default HTTP error response content in Tomcat 【发布时间】:2010-10-22 02:44:46 【问题描述】:

默认情况下,如果 Tomcat 遇到 HTTP 404 之类的问题,它会将一些 html 内容发送回客户端。我知道可以通过 web.xml<error-page> can be configured 自定义这些内容。

但是,我希望 Tomcat 在响应内容方面不发送任何内容(当然,我仍然想要状态码)。有什么方法可以轻松配置吗?

我试图避免 A) 从我的 Servlet 的响应流中显式发送空内容,以及 B) 在我的 web.xml 中为一大堆 HTTP 错误状态配置自定义错误页面。

对于某些背景,我正在开发一个 HTTP API 并控制我自己的响应内容。例如,对于 HTTP 500,我在包含错误信息的响应中填充了一些 XML 内容。对于像 HTTP 404 这样的情况,HTTP 响应状态对于客户端来说就足够了,而 Tomcat 正在发送的内容是不必要的。如果有不同的方法,我愿意听取。

编辑: 经过继续调查,我仍然找不到太多解决方案。如果有人可以明确地说这是不可能的,或者提供资源证明它不起作用,我会接受它作为答案并尝试解决它。​​

【问题讨论】:

我并没有强调代码的含义,而是按预期使用它们。这是针对 REST API - 例如,如果有人在我的 API 中对某个资源执行 GET,但我没有找到它,我将响应状态设置为 404。如果我有某种奇怪的错误,我将状态设置为 500 并在响应中提供了一些错误内容。但我希望对这些内容进行独占控制——我不希望 Tomcat 返回 HTML 或其他任何内容。如果要返回内容,我希望我的 Servlet 是这样做的。 我刚刚还发现 Servlet 3 似乎允许一个包罗万象的:static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/… @ErichEichinger - 这是有用的信息,感谢您传递它。 【参考方案1】:

虽然它符合 Servlet 规范,但出于安全原因,我不希望 tomcat 或任何其他 Servlet 容器发送错误详细信息。我也为此苦苦挣扎。经过搜索和尝试,解决方法可以总结为:

    正如其他人所说,不要使用sendError(),而是使用setStatus() (in Jersey framework you can choose) 框架,例如Spring Security 使用 sendError() 虽然... 写一个Filter那个 一种。将呼叫重定向到 sendError()setStatus() 湾。在最后刷新响应以防止容器进一步修改响应

A little example servlet filter doing this can be found here.

【讨论】:

+1 指出框架具有预定义的行为并提供示例过滤器,当我使用 Jersey 时,它让我发现了 a specific Jersey property @watery 发布的上述链接截至 2019 年已失效,现在正确的链接是 jersey.github.io/apidocs/latest/jersey/org/glassfish/jersey/… 链接又死了,最好看看this answer ;)【参考方案2】:

web.xml 中配置<error-page> 元素

编辑$CATALINA_HOME/conf/web.xml,在末尾添加<error-page>,保存并重启tomcat

<web-app>

...
...
...

    <error-page>
        <error-code>404</error-code>
        <location>/404.html</location>
    </error-page>

    <error-page>
        <error-code>500</error-code>
        <location>/500.html</location>
    </error-page>

    <error-page>
        <error-code>400</error-code>
        <location>/400.html</location>
    </error-page>

</web-app>

之前

之后

【讨论】:

你错过了 OP 说他 试图避免 [..] 为 [his] web.xml 中的一大堆 HTTP 错误状态配置自定义错误页面 . 同意。然而,它对那些用谷歌搜索示例的人很有帮助。这个问题有很好的 SEO 评级。【参考方案3】:

虽然这并没有完全响应问题上的“不发送任何东西”声明,并且在Clive Evans' answer 的浪潮中,我发现在tomcat中你可以让那些太多冗长的文本从错误页面中消失无需创建自定义 ErrorReportValve。

您可以通过“server.xml”上的 2 个参数“showReport”和“showServerInfo”来完成此自定义 ErrorReportValve:

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" />

Link to official documentation.

在 tomcat 7.0.55 上为我工作,在 tomcat 7.0.47 上不适合我(我认为是因为在以下链接 http://www.mail-archive.com/users@tomcat.apache.org/msg113856.html 上报告了一些内容)

【讨论】:

使用 Tomcat 8。优秀的解决方案! Tomcat 文档说 元素可以放在 server.xml 中的 元素中。对我来说,将阀门放在 元素中是行不通的,但将它放在单独的 元素中可以。文档还说 Tomcat 将任何不匹配的主机名路由到 元素的 defaultHost 属性中设置的 元素。为确保您的主机/上下文之外的位置的 URL 不会显示编译到 Tomcat 中的错误消息,您需要确保将此 添加到您的默认 【参考方案4】:

虽然这个问题有点老了,但我也遇到了这个问题。首先,Tomcat的行为是绝对正确的。这是每个 Servlet 规范。不应该根据规范改变 Tomcat 的行为。正如 Heikki Vesalainen 和 mrCoder 提到的,仅使用 setStatussetStatus

对于它可能关心的人,我已经向 Tomcat 提出了 ticket,以改进 sendError 的文档。

【讨论】:

你能澄清一下你所说的“绝对正确”的行为是什么意思吗?具体是哪种行为? Servlet 规范的链接或摘录可能会有所帮助。我在 3.0 规范中找不到任何解决响应实际内容要求的内容,特别是对于错误响应。就RFC2616 而言,对于任何错误状态的实体内容都没有任何要求。 是的,当然。这不受 RFC 约束,而是与 Servlet 规范本身有关。检查 Servlet 规范 3.0,第 10.9.2 和 10.9.3 章,Oracle 的 Servlet API JavaDocs 以了解 sendError 方法和我对 Tomcat Users Mailinglist 的问题。【参考方案5】:

阻止 Tomcat 发送任何错误主体的快速、有点脏但简单的方法是针对 tomcat 主机调用 setErrorReportValveClass,并使用自定义错误报告阀覆盖报告以不执行任何操作。即:

public class SecureErrorReportValve extends ErrorReportValve 

@Override
protected void report(Request request,Response response,Throwable throwable) 



并将其设置为:

  ((StandardHost) tomcat.getHost()).setErrorReportValveClass(yourErrorValveClassName);

如果您想发送您的消息,并且只是认为 Tomcat 不应该搞砸它,那么您需要以下内容:

@Override
protected void report(final Request request, final Response response, final Throwable throwable) 
    String message = response.getMessage();
    if (message != null) 
        try 
            response.getWriter().print(message);
            response.finishResponse();
         catch (IOException e) 
        
    

【讨论】:

这很棒!我喜欢有一个地方来控制它,而不是必须包装每一个响应。更加面向方面。 确实是更好的解决方案!谢谢 请随意指出规范中说您不应该使用 Tomcat ErrorReportValve 的部分,它会将您的消息重写为包含您可能不想与之共享的大量信息的消息外面的世界,而是只写你的信息。我很感兴趣...... 另外,您可以编写自己的 ErrorValve 并在 server.xml 的 元素中配置它: 见tomcat.apache.org/tomcat-7.0-doc/config/host.html 如果你不使用 Tomcat,你就不会被 Tomcat 泄露你的信息所困扰......【参考方案6】:

正如 Heikki 所说,设置状态而不是 sendError() 会导致 Tomcat 不接触响应实体/正文/有效负载。

如果您只想发送没有任何实体的响应标头,例如我的情况,

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);

成功了。使用Content-Length: 0,即使使用print()也没有效果,比如:

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.getWriter().print("this string will be ignored due to the above line");

客户端收到如下内容:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 0
Date: Wed, 28 Sep 2011 08:59:49 GMT

如果您想发送一些错误消息,请使用带有消息长度(不为零)的setContentLength(),或者您可以将其留给服务器

【讨论】:

【参考方案7】:

如果您不希望 tomcat 显示错误页面,请不要使用 sendError(...)。而是使用 setStatus(...)。

例如如果你想给出 405 响应,那么你就做

response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);      
response.getWriter().println("The method " + request.getMethod() + 
   " is not supported by this service.");

还要记住不要从您的 servlet 中抛出任何异常。而是捕获异常,然后再次设置您自己的状态代码。

protected void service(HttpServletRequest request,
      HttpServletResponse response) throws IOException 
  try 

    // servlet code here, e.g. super.service(request, response);

   catch (Exception e) 
    // log the error with a timestamp, show the timestamp to the user
    long now = System.currentTimeMillis();
    log("Exception " + now, e);
    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    response.getWriter().println("Guru meditation: " + now);
  

当然,如果你不想要任何内容​​,那么就不要给作者写任何东西,只要设置状态即可。

【讨论】:

使用 print() 而不是 println() 这会导致额外的新行字符。如果您使用Content-Length: 0 发送空字符串,这将特别有用 我认为这样做的真正原因是因为您已经写入了输出流。我相信,如果你只是简单的设置状态,不写任何响应,Tomcat 会发送默认的 405 错误响应。 仅仅设置状态码似乎不足以抑制标准错误页面(至少,不是根据我自己的经验)。 我必须在编写器上调用 flush() 以确保我的内容不会被 Tomcat 覆盖。 在抛出ClassNotFoundException 时似乎无法捕获异常。错误仍然出现【参考方案8】:

为什么不用空的 HTML 页面配置 &lt;error-page&gt; 元素?

【讨论】:

我在问题中提到我想避免为一堆状态配置错误页面(即使它们是空的)。如果这是我唯一的选择,那么我想我将不得不这样做 - 但我正在寻找替代方案。

以上是关于禁用Tomcat中所有默认的HTTP错误响应内容的主要内容,如果未能解决你的问题,请参考以下文章

tomcat的安全配置(禁用http方法,部署多个应用,启用从安全cookie,指定错误页面和显示信息)

复现CVE-2019-0232 Tomcat 远程代码执行

tomcat安全优化

Tomcat 7 sessionid cookie 禁用 http-only 和安全

http错误215545

是否可以在 tomcat servlet 中禁用 jsessionid?