Tomcat 8 安全加固的最佳实践

文章导读

在企业级 Java 开发环境中,Apache Tomcat 因其轻量、高效的特性,一直是作为首选的Web应用服务器。但"开源"不代表"开箱即用即安全"。随着如今 AI 自动化扫描工具盛行,Tomcat 的默认配置早已成为攻击者重点关照的"对象"。尤其是对于映射到公网或者部署在云服务器上的关键业务系统,如果只用默认配置,很容易导致敏感信息泄露、远程指令执行等严重风险。

为了满足等保 2.0 的要求,也为了Web应用服务器的稳健运行,必须要进行有针对性的加固。下面我整理了 15 条针对 Tomcat 8 的加固建议,从底层配置到应用边界,希望能帮大家排查并封堵最容易被忽视的安全隐患。

一、严格控制运行权限(最小权限)

不要以 root 用户身份运行 Tomcat,这条规则适用于大多数 Web 服务器平台。不应使用具有最高权限的管理员账户运行 Web 相关服务。以 Tomcat 为例,应创建一个仅具有最小权限的普通账号,专门用于运行 Tomcat 进程。

操作实例

1. 创建专用用户与组

properties 复制代码
# 创建 tomcat 用户组
groupadd tomcat
# 创建用户,指定 Shell 为 /bin/false (禁止登录),并设置home目录
useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat

2. 设置目录属主权限

perl 复制代码
# 递归更改tomcat目录的所有权
chown -R tomcat:tomcat /opt/tomcat

# 仅赋予目录文件的所有者具备读写权限,其他人无权限
chmod -R 750 /opt/tomcat

3. 配置 Tomcat 服务启动文件

ini 复制代码
[Unit]
Description=Apache Tomcat Web Application Server
After=network.target

[Service]
Type=forking

# 指定运行用户
User=tomcat
Group=tomcat

# 配置 Java 环境与启动参数
Environment="JAVA_HOME=/usr/lib/jvm/java-8-openjdk"
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

二、删除默认的示例与文档

大多数 Web 服务器在初始安装时,会自带一些测试用的 Demo 示例。这些示例通常只是为了让用户快速上手,并非生产环境必须。不仅没用,反而往往自带已知漏洞,极易成为攻击者的入侵切入点。

默认目录说明

  • **ROOT:**默认首页,包含一些系统信息页面(如 Tomcat 版本号),建议删除此目录下所有文件(不要删除此目录),然后使用自己的项目目录替代。

  • **examples:**演示应用目录,包含了大量的 JSP 和 Servlet 示例,安全隐患最高,建议删除。

  • **docs:**Tomcat 的在线文档,虽然危害较小,但会暴露中间件信息,建议删除。

  • **manager:**Tomcat的管理后台,如果你不需要通过 Web 界面远程部署应用,必须删除或禁用它,否则它将成为暴力破解的首要目标。

  • **host-manager:**虚拟主机管理程序,同上,建议删除。

操作实例

properties 复制代码
# 进入 Webapps 目录
cd /opt/tomcat/webapps
# 删除root下的默认文件
rm -rf ROOT/*

# 删除示例与文档
rm -rf examples docs

# 根据需求删除管理控制台
rm -rf manager host-manager

禁止 Tomcat 关机指令远程调用

Tomcat 的远程关机端口,往往是容易被忽视的隐患。如果不加限制,攻击者可以通过发送简单的指令直接终止 Web 服务。如果业务系统不需要远程关机功能,最保险的操作是在 server.xml 中将 port 直接设为 -1,从根源上断绝此路径。若因特殊环境必须开放该接口,务必修改默认指令并设置的足够复杂,以避免非授权的恶意指令执行。

操作实例

1

使用 sed 命令禁用 Shutdown 端口

apache 复制代码
# 将/opt/tomcat替换为实际环境下的tomcat目录
sed -i 's/port="8005"/port="-1"/' /opt/tomcat/conf/server.xml

2

将shutdown设置为强密码

Tomcat 的 shutdown 属性其键值对应的并不是一个"密码",而是一个可执行的"关闭指令"。

apache 复制代码
# 替换掉默认的SHUTDOWN键值
sed -i 's/shutdown="SHUTDOWN"/shutdown="DoNot@2026!ShutDown"/' /opt/tomcat/conf/server.xml

禁用跟踪请求的功能

尽管 allowTrace 在日常调试中很顺手,但它往往是 XSS 攻击的对象。在生产环境部署Tomcat时,务必记得在 server.xml 中将该选项关闭。通过禁用 HTTP TRACE 方法,可以从源头上消除这一潜在的安全漏洞,这也是目前 Tomcat 生产环境安全加固的必选项

操作实例

在文件 server.xml 的 标签中,修改 allowTrace 属性

xml 复制代码
<Connector port="8080" protocol="HTTP/1.1" allowTrace="false" ... />

禁止发送 X-Powered-By 响应头

在生产环境中,应尽量减少服务器的"信息暴露面"。Tomcat 默认开启的 xpoweredBy 会主动通过 HTTP 响应头向外界公开自己的版本号,这也方便攻击者进行靶向入侵。建议务必在 server.xml 中关闭该属性,防止内部服务底层细节通过响应头被暴露。

操作实例

在文件 server.xml 的 标签中,修改 xpoweredBy 属性

xml 复制代码
<Connector port="8080" protocol="HTTP/1.1" xpoweredBy="false" ... />

禁用 SSLv3 以防止 POODLE 攻击

早在 2014 年爆发的贵宾犬漏洞(又称 POODLE 漏洞),彻底终结了 SSL v3 协议的安全性。该漏洞允许攻击者通过此协议降级拦截敏感信息,如用户的账户密码及浏览器 Cookie 等。为了规避此类风险,生产环境中必须彻底摒弃 SSL v3 及所有老旧的 SSL 版本。建议在 server.xml 的 sslEnabledProtocols 配置项中,仅启用 TLS 1.2 及以上版本,只保留最坚固的加密通道。

操作实例

在文件 server.xml 的 标签中,修改 sslEnabledProtocols 属性

makefile 复制代码
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           sslEnabledProtocols="TLSv1.2,TLSv1.3"
           ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
           keystoreFile="..." keystorePass="..." />

设置 DeployXML 属性为 False

在共享托管环境下,为了防止恶意程序通过篡改 context.xml 等配置文件来越权提升权限,强烈建议将 deployXML 属性设为 false。这一配置能够切断 Web 应用对外部 XML 部署描述符的依赖,防止攻击者利用伪造或被注入恶意代码的配置文件对系统进行权限欺骗。对于运行多个应用且信任边界不明确的服务器而言,这是限制横向渗透的唯一方式

操作实例

在文件 server.xml 的 标签中,修改 deployXML 属性

xml 复制代码
<Host name="localhost"  appBase="webapps" unpackWARs="true" 
      autoDeploy="true" deployXML="false">

合理配置和使用领域

Realm是Tomcat中为web应用程序提供访问认证和角色管理的机制。配置了Realm,你就不需要在程序中写web应用登陆验证代码,不需要费力的管理用户角色,甚至不需要你自己写登陆界面。因此,使用Realm可以减轻开发者不少编程和管理负担。

而针对 Tomcat Realm 的选型,建议遵循"性能优先、架构成熟"的原则。生产环境建议通过 DataSourceRealm 来处理身份校验,因为它能利用连接池高效支撑并发请求;反观 JDBCRealm,由于其内部采用单线程处理逻辑,根本无法应对高频次的认证请求。另外,对于 JAASRealm,考虑到其应用基数较小且项目成熟度欠佳,除非有极特殊的架构需求,否则不推荐作为首选方案。

操作实例

1

JDBCRealm (不推荐用于生产环境)

这是最简单的实现方式,直接连接数据库进行校验。但性能差,因为它是单线程的,且每次验证都会建立新的连接。

xml 复制代码
<Realm className="org.apache.catalina.realm.JDBCRealm"
       connectionURL="jdbc:mysql://localhost:3306/mydb"
       connectionName="dbuser"
       connectionPassword="dbpassword"
       userTable="users"
       userNameCol="username"
       userCredCol="password"
       userRoleTable="user_roles"
       roleNameCol="role_name" />

2

DataSourceRealm (生产环境推荐)

通过配置全局 JNDI 数据源,支持连接池复用,可实现高效认证。

  • **第一步:**在 server.xml 的 标签中定义数据源:
bash 复制代码
<Resource name="jdbc/MyPool" auth="Container" type="javax.sql.DataSource"
          maxActive="100" maxIdle="30" maxWait="10000"
          username="dbuser" password="dbpassword"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://localhost:3306/mydb"/>
  • **第二步:**在 或 标签中配置 Realm:
xml 复制代码
<Realm className="org.apache.catalina.realm.DataSourceRealm"
       dataSourceName="jdbc/MyPool"
       userTable="users"
       userNameCol="username"
       userCredCol="password"
       userRoleTable="user_roles"
       roleNameCol="role_name" />

3

JAASRealm (极少使用,维护复杂)

基于 Java 认证和授权服务 (JAAS) 的实现。极其灵活,可以整合 LDAP、Kerberos 或自定义复杂的认证逻辑,但配置非常繁琐,涉及 JAAS 配置文件和类路径设置,极易出错。

xml 复制代码
<Realm className="org.apache.catalina.realm.JAASRealm"
       appName="MyJaasApp"
       userClassNames="com.myapp.MyUserPrincipal"
       roleClassNames="com.myapp.MyRolePrincipal" />

**注意:**使用此方式还需要额外配置 jaas.config 文件,通常需要丰富的 Java 开发背景,具体不做讲解。

为每个请求创建新的 Facade 对象

为了从底层杜绝请求间数据泄露的风险,可以将 Tomcat 设置为为每个请求实例化独立的 Facade 对象。通过在 JVM 启动参数中添加下面的参数,可以强制 Tomcat 在处理完每个请求后立即回收 Facade 对象。这种做法虽然会带来极其细微的性能损耗,但能有效防止因应用程序逻辑缺陷(Bug)导致的用户数据污染或数据串用,是高安全敏感场景下的一种"防御性配置"

操作实例

修改 Tomcat 的启动脚本,通常路径为 bin/setenv.sh

bash 复制代码
# 在 setenv.sh 中添加以下内容
export CATALINA_OPTS="$CATALINA_OPTS -Dorg.apache.catalina.connector.RECYCLE_FACADES=true"

确保资源访问权限设置为只读

通过将 DefaultServlet 中的 readonly 属性设为 true,可以为服务器静态资源加上一道"写保护"锁。这一配置能有效拦截客户端发起的非法写操作,从根本上防止服务器上的静态资源被恶意删除、篡改或上传伪造文件。对于生产环境而言,这是一种防御非法资源篡改、加固 Web 目录权限的必要手段。

操作实例

从配置文件 conf/web.xml 的 Servlet 标签中,修改 default 的参数,将其配置为只读:

xml 复制代码
<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>readonly</param-name>
        <param-value>true</param-value>
    </init-param>
    ...
</servlet>

十一

禁用 Tomcat 显示目录列表

在生产环境中,如果目录文件较多,开启列表功能会消耗大量系统资源,因此可能招致来源外界的拒绝服务(DDoS)攻击。通过将 DefaultServlet 的 listings 属性设置为 false,可以彻底关闭该功能,从源头上消除这一潜在的攻击威胁。

操作实例

从配置文件 conf/web.xml 的 Servlet 标签中,找到 default 参数,参考下面格式添加或修改 init-param 属性:

xml 复制代码
<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value> </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

十二

启用网络流量日志记录

生产环境中应建立完善的日志体系,特别是网络访问日志(Access Log),它是安全评估与行为追溯的关键。建议通过配置 AccessLogValve 参数来精细化流量日志。

操作实例

在配置文件 server.xml 的 标签中添加以下配置,开启详细的访问日志记录:

perl 复制代码
<Valve className="org.apache.catalina.valves.AccessLogValve" 
       directory="logs"  
       prefix="localhost_access_log" 
       suffix=".txt"
       pattern="%h %l %u %t &quot;%r&quot; %s %b %D" 
       resolveHosts="false" />

**注意:**务必包含 %D(记录请求处理耗时),这在分析性能瓶颈或识别恶意攻击资源消耗(DDoS)时非常有效。

十三

禁用自动部署

如果你已构建完善的 CI/CD 流水线,完全可以发挥 Tomcat 自动部署功能的优势。但若未建立,务必将 autoDeploy、deployOnStartup 及 deployXML 属性全部设为 false,这是防御攻击者通过自动化部署机制篡改应用或植入恶意脚本的必要设置。

操作实例

在 配置文件 server.xml 的 标签中修改上面的三个属性:

xml 复制代码
<Host name="localhost" 
      appBase="webapps" 
      unpackWARs="true" 
      autoDeploy="false" 
      deployOnStartup="false" 
      deployXML="false">
    ...
</Host>

十四

禁用或限制 Tomcat 管理器

通过 Tomcat Manager 的 Web 界面部署管理项目实例虽然方便,但对管理员和攻击者来说是一把"双刃剑"。相比之下,采用非 Web 方式会更加稳妥。如果生产环境确实离不开它,务必通过更加严格的安全配置来减小被攻击的可能性。

操作实例

1限制访问 IP

修改配置文件 webapps/manager/META-INF/context.xml

xml 复制代码
<Context ...>
  <Valve className="org.apache.catalina.valves.RemoteAddrValve" 
         allow="127\.0\.0\.1|192\.168\.1\.100" />
</Context>

2配置强密码

修改配置文件 conf/tomcat-users.xml

xml 复制代码
<tomcat-users>
  <role rolename="manager-script"/>
  <user username="ops_admin" password="[强密码]" roles="manager-script"/>
</tomcat-users>

3拒绝使用 admin 角色

  • 拒绝使用 admin 角色。

  • 仅赋予 manager-script 权限用于 CI/CD 自动化;如果必须通过浏览器访问,仅赋予 manager-gui 权限。

xml 复制代码
<tomcat-users>
  <role rolename="manager-gui"/>    <role rolename="manager-script"/> <user username="cicd_deployer" password="[强密码]" roles="manager-script"/>
  <user username="ops_human" password="[强密码]" roles="manager-gui"/>
</tomcat-users>

4彻底物理隔离(推荐)

properties 复制代码
# 停止 Tomcat
# 删除Web管理目录
rm -rf /opt/tomcat/webapps/manager
rm -rf /opt/tomcat/webapps/host-manager
# 重启 Tomcat

十五 限制连接器的可用性

为了提升安全性,Tomcat 的连接器(Connector)不应默认监听所有网卡接口。建议通过配置 address 属性,将其强制绑定至 Web 应用所需的特定 IP,从而切断多余接口的监听流量,最大程度地减少攻击面。

操作实例

在配置文件 server.xml 中找到 标签,明确指定监听地址,而非留空(默认为 0.0.0.0):

xml 复制代码
<Connector port="8080" protocol="HTTP/1.1" address="192.168.1.100" ... />