Tomcat 8.5版本以上隐藏400报错信息

一个平时没注意过的问题。

从Tomcat 8.5版本开始,若URL中存在部分特殊字符,会产生400报错。本以为修复方法和其他404、5XX报错页面没什么不同,结果并不简单。因为这个400报错是由于Tomcat无法解析字符导致的报错,并不通过代码层面,所以一般的错误页面自定义配置就会失效。

隐藏Tomcat 400报错

报错如下图所示:

400-error

查看Tomcat文档 https://tomcat.apache.org/tomcat-8.5-doc/config/http.html ,其中relaxedPathCharsrelaxedQueryChars中写明,若存在" < > [ \ ] ^ ` { | }符号,Tomcat无法解析URI,产生报错。

所以必须采用其他方法进行修复,这里提供隐藏报错详细信息的修复方式。

server.xml中添加一个ErrorReportValve,将showReport设置为false就隐藏了详细报错信息,showServerInfo设置为false是隐藏Tomcat版本信息。

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

重启Tomcat,再次访问效果如下:

hide-400-error

虽然没有彻底自定义界面,但好歹也隐藏掉了报错信息。

附加

本地快速复现漏洞,得善用docker。通过docker可以快速构造好需要的环境,可能节省很多亲自搭建环境的时间,如果让我自己来搭的话指不定要多久,说不定还会碰到各种环境不兼容的问题,有现成的直接用就非常爽了。比如这里我需要tomcat 9,直接在dockerhub上搜索tomcat9,然后随便点击进一个项目。

docker-search

复制Docker Pull Command,在命令行中输入,即可把镜像拉下来

docker-search-2

镜像拉下来后,启动镜像

1
docker run -it --rm -p 8888:8080 donglsheng/tomcat9_jdk8

其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开,--rm是在运行完成之后清除容器,-p是指定映射端口,其中8888是容器外端口,8080是容器内端口。

docker-run

这样启动并不能得到一个交互式的shell,如果需要执行容器内命令,在后方加上/bin/bash就是进入容器内的shell。

1
docker run -it --rm -p 8888:8080 donglsheng/tomcat9_jdk8 /bin/bash

进入docker后,可能找不到相关的路径,这时需要去查找该镜像的制作人在Docker Hub中有没有写明路径或相关教程。没有的话再看容器启动时是否会显示路径。

Dockerfile中都会写明具体路径

dockerfile-path

进入shell后查找该路径即可找到tomcat的位置。

exec-docker

cd /usr/local/soft/tomcat/就到了tomcat目录,其中conf目录就是配置文件所在的目录,需要更改的server.xml就在该路径下

tomcat-conf-path