SpringBoot应用配置*目标仅允许GET、POST HTTP方法实现方案
常规Spring MVC层的拦截配置(包括HandlerInterceptor、@RequestMapping method属性限定、Spring Security路径拦截规则)只能覆盖DispatcherServlet处理的业务路径请求,无法修改内嵌Web容器对*通用目标路径OPTIONS请求的默认响应——这也是此前方案失效的核心原因:容器默认的DefaultServlet会提前拦截这类通配路径请求,直接返回内置的全量允许方法列表,请求根本不会进入Spring的处理链路。
方案1:高优先级全局Filter(全容器兼容,首选)
该方案不依赖特定内嵌容器实现(Tomcat/Jetty/Undertow均适用),通过最高优先级的Filter在请求进入容器默认处理逻辑前完成拦截,手动控制响应规则:
import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component @Order(Ordered.HIGHEST_PRECEDENCE) public class GlobalHttpMethodLimitFilter implements Filter { // 配置全局允许的HTTP方法 private static final String ALLOWED_METHODS = "GET,POST"; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpResp = (HttpServletResponse) response; String requestMethod = httpReq.getMethod(); // 1. 专门处理针对*通配路径的OPTIONS请求,直接返回自定义Allow头 if ("OPTIONS".equalsIgnoreCase(requestMethod) && "*".equals(httpReq.getRequestURI())) { httpResp.setHeader("Allow", ALLOWED_METHODS); httpResp.setStatus(HttpServletResponse.SC_OK); return; } // 2. 拦截所有非允许方法的请求,直接返回405状态码 boolean isMethodAllowed = "GET".equalsIgnoreCase(requestMethod) || "POST".equalsIgnoreCase(requestMethod); // 若需要兼容HTTP协议默认的HEAD方法(HEAD为无响应体的GET请求,无额外安全风险),可放开下面这行注释 // isMethodAllowed = isMethodAllowed || "HEAD".equalsIgnoreCase(requestMethod); if (!isMethodAllowed) { httpResp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } chain.doFilter(request, response); } }
如果项目集成了Spring Security,需要额外在Security配置中关闭默认的OPTIONS自动处理逻辑,避免配置被覆盖:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .cors(Customizer.withDefaults()) // 关闭Security默认的OPTIONS请求自动响应逻辑 .requestCache().disable() .authorizeHttpRequests(auth -> { // 业务路径权限规则按实际需求配置即可 auth.anyRequest().authenticated(); }); return http.build(); } }
方案2:Tomcat原生配置(无额外Filter开销)
如果项目使用Spring Boot默认的Tomcat内嵌容器,可直接自定义Tomcat配置,修改DefaultServlet的初始化参数,从容器层面限制允许的方法:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TomcatHttpMethodConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatMethodLimitCustomizer() { return factory -> factory.addContextCustomizers(context -> { // 配置Tomcat全局允许的HTTP方法 context.setAllowSemicolonContent(false); // 给默认Servlet设置允许方法列表,替换默认返回的Allow头 context.getServletRegistration("default").addInitParameter("allow", "GET,POST"); // 禁用TRACE等危险方法 context.setUseHttpOnly(true); }); } }
验证方式
配置完成后重启服务,用之前的测试命令验证即可:
- 执行nikto扫描命令:
nikto -ssl -h https://localhost:8181,扫描结果中允许的HTTP方法仅显示GET、POST,不会再出现PUT/DELETE等方法的风险提示 - 执行curl测试命令:
curl -k -i --request-target "*" -X OPTIONS https://localhost:8181,返回响应中Allow头的值为GET,POST,状态码为200 - 发送PUT/DELETE等其他方法请求任意路径,均会返回
405 Method Not Allowed响应。
补充说明:部分HTTP客户端和扫描工具会默认将HEAD方法识别为允许方法,该行为符合HTTP RFC规范——HEAD本质是不返回响应体的GET请求,服务端支持GET就必然支持HEAD,不存在文件写入、删除等安全风险。如果客户强制要求Allow头中不出现HEAD字段,删掉Filter代码中HEAD方法放行的注释逻辑即可。
内容的提问来源于stack exchange,提问作者Philippe MESMEUR

