前言
2020 年 1 月 6 日,国家信息安全漏洞共享平台(CNVD)收录了由北京长亭科技有限公司发现并报送的 Apache Tomcat 文件包含漏洞。Tomcat AJP 协议由于存在实现缺陷导致相关参数可控,攻击者利用该漏洞可通过构造特定参数,读取服务器 webapp 下的任意文件。若服务器端同时存在文件上传功能,攻击者可进一步实现远程代码的执行。
Tomcat AJP 协议的这种实现缺陷,对于 SpringBoot 开发的 web 应用是否受影响了?且听笔者一一道来。
AJP 协议
根据 apache 官网 AJP 协议相关介绍:
The original document was written by Dan Milstein, danmil@shore.net on December 2000.
Overview of the protocol
The ajp13 protocol is packet-oriented. A binary format was presumably chosen over the more readable plain text for reasons of performance. The web server communicates with the servlet container over TCP connections. To cut down on the expensive process of socket creation, the web server will attempt to maintain persistent TCP connections to the servlet container, and to reuse a connection for multiple request/response cycles.
Once a connection is assigned to a particular request, it will not be used for any others until the request-handling cycle has terminated. In other words, requests are not multiplexed over connections. This makes for much simpler code at either end of the connection, although it does cause more connections to be open at once.
AJP13 协议全称为 Apache JServ Protocol version 1.3 ,最初由 Dan Milstein 于2000年12月发表,后被 Apache 软件基金会 Jakarta 项目采纳。
AJP13 是一种二进制 TCP 传输协议,通过在网络传输二进制包(packet)来完成 Tomcat 与 http 服务器的请求与响应,显然这种方式比纯文本(如 text、xml等)传输的 http 协议效率要高的多。
但是 AJP13 协议对浏览器支持不够好,由于其定位是 “ Tomcat 与 HTTP 服务器之间通信的协议”,这或许是 http 协议比较盛行的原因吧。
说完了 Tomcat AJP13 协议的来龙去脉,接着,进入主题。
SpringBoot 为什么这么火?
spring-boot-starter-web
对 Spring 比较熟悉的话, 基于 SpringBoot 开发 web 应用时,引入 spring-boot-starter-web 组件是必不可少的,spring-boot-starter-web 的职责是负责 web 应用的启动 、初始化、运行和停止。而 spring-boot-starter-web 组件之所以能够跑起来,少不了 http 协议的支持,典型代表就是 tomcat 服务器。
通过翻阅 spring-boot-starter-web 组件的相关 maven 依赖,我们找到了 spring-boot-starter-tomcat 组件。
org.springframework.boot spring-boot-starter-tomcat 2.1.5.RELEASE compile
接着查找 spring-boot-starter-tomcat 的 maven 依赖, 其引入了 tomcat-embed-core 、tomcat-embed-el 、tomcat-annotations-api 等嵌入式组件。
javax.annotation javax.annotation-api 1.3.2compileorg.apache.tomcat.embed tomcat-embed-core 9.0.19compile tomcat-annotations-api org.apache.tomcatorg.apache.tomcat.embed tomcat-embed-el 9.0.19compileorg.apache.tomcat.embed tomcat-embed-websocket 9.0.19compile
正是由于这些嵌入式组件的加入,免去了 Tomcat 单独安装部署的繁杂步骤,我想这也是 SpringBoot 非常火的原因之一吧。
SpringBoot 对 AJP 协议的支持
通过阅读 tomcat-embed-core 组件,说明嵌入式 tomcat 是支持 AJP 协议的,相关代码在 org.apache.coyote.ajp 目录下。
但是奇怪的是,在 SpringBoot 的 yml 文件配置中,并没有找到 ajp 协议相关的 server 参数配置。
笔者猜测,虽然 Tomcat 集成了 ajp 协议,但是不推荐使用吧。但是有没有办法支持 ajp 协议了,答案是可以的,具体代码如下:
@Configurationpublic class AJPConfig { private static final String PROTOCOL = "AJP/1.3"; @Value("${tomcat.ajp.port:8009}") private int ajpPort; @Bean public EmbeddedServletContainerFactory servletContainer() { TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(); Connector ajpConnector = new Connector(); ajpConnector.setProtocol(PROTOCOL); ajpConnector.setPort(ajpPort); tomcat.addAdditionalTomcatConnectors(ajpConnector); return tomcat; }}
笔者上述配置需要依赖 SpringBoot 1.x 环境。
AjpProcessor
如果对 tomcat 架构比较了解的话,tomcat 大部分请求与响应由协议(Protocol)中的处理器(Processor)完成的。
所以在 tomcat 服务器接收 ajp 请求时, 由 AjpProcessor 来处理 ajp 真实的 request 请求消息。
然后,通过 prepareRequest 方法将 ajp 请求内容取出来,设置成 request 对象的 Attribute 属性
因此,黑客通过设置 request_uri、path_info 、servlet_path 属性值,从而可以读取到 /WEB-INF 下面的所有敏感文件,不限于class、xml、jar等文件。
javax.servlet.include.request_urijavax.servlet.include.path_infojavax.servlet.include.servlet_path
至于漏洞的详细分析不是本文重点,传送门:
https://blog.csdn.net/u012206617/article/details/104416626/