SpringBoot内嵌Tomcat Allow头硬编码致漏洞 如何仅开放GET/POST方法
SpringBoot OPTIONS *请求Allow响应头硬编码问题修复方案
问题背景
- 对SpringBoot应用开展渗透测试过程中,检测到两项HTTP方法配置相关安全风险。
- 执行nikto扫描命令
nikto -ssl -h https://localhost:8181返回如下告警:
+ Allowed HTTP Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS + OSVDB-397: HTTP method ('Allow' Header): 'PUT' method could allow clients to save files on the web server. + OSVDB-5646: HTTP method ('Allow' Header): 'DELETE' may allow clients to remove files on the web server.
- 执行curl探测命令
curl -k -i --request-target "*" -X OPTIONS https://localhost:8181可稳定复现该问题,响应头中Allow字段值固定为GET, HEAD, POST, PUT, DELETE, OPTIONS。 - 此前尝试调整SpringBoot常规配置,目标是让响应头仅返回
Allow: GET, POST,但未达到预期效果。 - 源码排查确认:针对
OPTIONS *请求的处理逻辑位于Tomcat的CoyoteAdapter类中,核心代码片段如下:
protected boolean postParseRequest(org.apache.coyote.Request req, Request request, org.apache.coyote.Response res, Response response) throws IOException, ServletException { ... if (undecodedURI.equals("*")) { if (req.method().equalsIgnoreCase("OPTIONS")) { StringBuilder allow = new StringBuilder(); allow.append("GET, HEAD, POST, PUT, DELETE, OPTIONS");
- 该处
Allow字段值为Tomcat底层硬编码实现,无法通过Spring常规配置修改,需要可落地的方案规避该类漏洞检测。
备注:本问题为两个同主题Spring Web应用HTTP方法限制问题的后续延伸,核心诉求是覆盖全场景将应用对外允许的HTTP方法限制为GET、POST。
可行解决方案
方案1:应用层添加Servlet过滤器拦截重写响应头
该方案侵入性最低,无需修改Tomcat底层逻辑,仅需在应用中新增自定义过滤器,匹配到OPTIONS *请求时直接覆盖Allow响应头即可,示例代码如下:
import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter(filterName = "allowMethodRewriteFilter", urlPatterns = "/*") public class AllowMethodRewriteFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpResp = (HttpServletResponse) response; // 匹配OPTIONS *请求 if ("OPTIONS".equalsIgnoreCase(httpReq.getMethod()) && "*".equals(httpReq.getRequestURI())) { httpResp.reset(); httpResp.setHeader("Allow", "GET, POST"); httpResp.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(request, response); } }
适配说明:SpringBoot 2.x版本使用javax.servlet包,将上述代码中jakarta开头的包路径替换为javax即可;启动类需要添加@ServletComponentScan注解以扫描注册该过滤器。
方案2:自定义Tomcat适配器替换硬编码逻辑
如果不希望在过滤器链路增加额外处理逻辑,可以自定义CoyoteAdapter子类,重写postParseRequest方法中拼接Allow字段的逻辑,再通过TomcatServletWebServerFactory将自定义适配器注册到Tomcat容器中,替换原有硬编码实现。
方案3:前置网关层拦截修改响应
如果应用前端部署了Nginx、API网关等反向代理组件,可以直接在网关层匹配OPTIONS *请求,直接返回自定义的Allow响应头,无需修改任何应用代码,Nginx配置示例如下:
server { listen 8181 ssl; # 省略SSL证书、域名等基础配置 location / { if ($request_method = OPTIONS) { if ($request_uri = "*") { add_header Allow "GET, POST" always; return 200; } } proxy_pass http://后端SpringBoot应用服务地址; } }
风险补充说明:Tomcat硬编码返回PUT、DELETE方法仅为OPTIONS探测响应的默认值,只要Spring侧没有配置对应路径的PUT/DELETE接口映射,攻击者无法实际调用这些方法执行文件上传、删除操作,Nikto的告警属于配置类风险提示,确认无对应危险接口暴露的情况下不存在可直接利用的实际漏洞。
内容的提问来源于stack exchange,提问作者Philippe MESMEUR
相关产品推荐
相关产品推荐

