1.什么是AJP协议?

springboot中对应的tomcat的AJP协议及漏洞解决_spring

HTTP协议:连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。  
AJP协议:连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。所以它的定位就是 “ Tomcat 与 HTTP 服务器之间通信的协议

AJP 是一种二进制 TCP 传输协议,通过在网络传输二进制包(packet)来完成 Tomcat 与 http 服务器的请求与响应,显然这种方式比纯文本(如 text、xml等)传输的 http 协议效率要高的多。

2.AJP存在的漏洞

2020 年 1 月 6 日,国家信息安全漏洞共享平台(CNVD)收录了由北京长亭科技有限公司发现并报送的 Apache Tomcat 文件包含漏洞。Tomcat AJP 协议由于存在实现缺陷导致相关参数可控,攻击者利用该漏洞可通过构造特定参数,读取服务器 webapp 下的任意文件。若服务器端同时存在文件上传功能,攻击者可进一步实现远程代码的执行。

漏洞影响版本:

  • 7.*分支7.0.100之前版本,建议更新到7.0.100版本;
  • 8.*分支8.5.51之前版本,建议更新到8.5.51版本;
  • 9.*分支9.0.31之前版本,建议更新到9.0.31版本。

3.springboot中与tomcat相关的依赖

基于 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 组件的,而spring-boot-starter-tomcat 的 maven 依赖又引入了 tomcat-embed-core 、tomcat-embed-el 、tomcat-annotations-api 等嵌入式组件。

正是由于这些嵌入式组件的加入,才免去了 Tomcat 单独安装部署的繁杂步骤。

4.springboot解决AJP漏洞方法

springboot中是默认不启用AJP的,如果需要开启还需要手动配置。

这一点可以从下图验证(如果已经开启AJP的话启动的日志信息中会包含以下信息)

springboot中对应的tomcat的AJP协议及漏洞解决_tomcat_02

springboot 1.x 手动配置AJP:

@Configuration
public 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 2.x 手动配置AJP:

@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainer() {
return server -> {
if (server instanceof TomcatServletWebServerFactory) {
((TomcatServletWebServerFactory) server).addAdditionalTomcatConnectors(redirectConnector());
}
};
}

private Connector redirectConnector() {
Connector connector = new Connector("AJP/1.3");
connector.setScheme("http");
connector.setPort(ajpPort);
connector.setSecure(false);
connector.setAllowTrace(false);
return connector;
}

如果使用的是外置tomcat

(1)编辑 <CATALINA_BASE>/conf/server.xml,找到如下行(<CATALINA_BASE> 为 Tomcat 的工作目录):
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
(2)将此行注释掉(也可删掉该行):
<!--<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />-->

(3)保存后需重新启动,规则方可生效。

如果springboot(使用默认内置tomcat)并没有手动开启AJP,那么你可以不升级tomcat内置版本。当然你想升级也可以。

如果使用的是springboot的内置tomcat,且手动开启了AJP协议,则需要升级内置tomcat版本。下面贴出一种我亲测可行的方法:

正常情况下每个springboot的版本都会带有一个内置的默认的tomcat,如果需要升级的话,我们可以直接去更改maven库中的该springboot的pom文件中tomcat的版本号即可,以Spring Boot ::       (v1.5.22.RELEASE)为例

我们进入 repository/org/springframework/boot/spring-boot-dependencies/1.5.12.RELEASE/目录中

编辑修改spring-boot-dependencies-1.5.12.RELEASE.pom文件的

<tomcat.version>8.5.43</tomcat.version>

改为

<tomcat.version>8.5.51</tomcat.version>

即可完成内置tomcat升级(记得编辑完之后刷新一下项目的Maven依赖)