【Bug解决思路】Tomcat返回不安全的响应头

2022-11-01 18:14:04 浏览数 (1)

背景概述

公司安全测试要求接口的请求方法只能是GET, POST,并且响应头也只能为GET, POST.

问题描述

在了解到这个需求后,我在过滤器对所有进入服务的请求统一设置响应头:

代码语言:javascript复制
@WebFilter(urlPatterns = "/*", filterName = "GlobalFilter")
public class GlobalFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {
        log.info(">>>>>>>>>>>>>>>>>>>> doFilter <<<<<<<<<<<<<<<<<<<<");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
        filterChain.doFilter(servletRequest, response);
    }
}

写这段代码是因为我下意识地认为只要设置一个全局的响应头,将 Access-Control-Allow-Methods 设置为GET,POST 就可以轻松实现测试提出的,响应头只能为GET, POST的需求.

这段代码帮我解决了大部分问题,我在自测时“GET,HEAD,POST,PUT,DELETE,OPTIONS”它们的响应头都成功返回了 GET、POST。贴一张 OPTIONS 请求的截图,他的Allow-Methos成功的返回了 GET,POST.

到这你是不是觉得问题就已经解决了?

并没有,事情没这么简单,测试很快就让我打脸了,请看下图,当 uri 改为 * 时,Allow 的返回值让我不敢相信自己的眼睛。

问题分析

在使用 burpsuite 复现问题时,我发现服务的过滤器并没有拦截到 options * 请求,也就是说请求在进入过滤器前就已经被处理并响应了。

那么Filter之前可能会有哪些容器处理 OPTIONS * 请求了呢?

解决方案

找出问题的原因后,我提出了两个解决方案:

方案一:增加一个新的中间件来拦截请求处理不安全的请求方法,例如: Nginx。

方案二:修改Tomcat Adapter, 去除 allow.append("GET,HEAD,POST,PUT,DELETE,OPTIONS").

让我猜猜,故事到这你是不是会秒选方案二。

一旦选择方案二,恶梦就开始了,因为Tomcat 不能直接修改 Adapter, 你以为只需要修改一行代码,实际上你需要重写 ”整个“ Tomcat, 下回我专门写篇长文来讲讲具体是怎么个重写法。

如果选择方案一,恭喜你今天可以正常下班了。

代码语言:javascript复制
location * {
    if ($request_method = OPTIONS ) {
        add_header Content-Length 0;
        add_header Content-Type text/plain;
    		add_header 'Access-Control-Allow-Methods' 'GET, POST';
        return 200;
    }
}

思考

其实整篇文章看完,会发现我其实只是解决了一个很小的问题,所以我想说的是本篇的重点并不是问题的答案,而是分析并解决问题的思路。

到这你以为就结束了吗?不,其实我还想说一点东西 。

方案的设计目的是实现业务目标,不是为了设计而设计引入各种高大上的中间件,技术自嗨。

虽然引入 Nginx 可以很方便的解决问题,但是它也会带来新的安全风险。系统中的元素越多,为了维持系统的平衡,需要付出的势能必然也越大。系统拆解的粒度越大,各个组件之间的耦合越小,但是解决的组件间协同问题也就越多。在系统设计时,要避免过度设计,把握技术方案的核心目的,在这个基础上进行针对性设计。

0 人点赞