Java Web应用如何防范请求查询参数导致的响应头及Cookie注入问题
问题本质
这是典型的查询参数反射型响应头注入漏洞,你当前写的过滤器只是做放行逻辑,没有额外操作,所以问题出在应用链路的其他环节:大概率是反向代理配置错误、框架全局默认配置、其他全局拦截器/过滤器存在「自动遍历查询参数批量添加到响应头」的逻辑,低版本Spring Boot、Spring Cloud Gateway组件、或者Nginx/Apache的通配add_header配置都可能触发该问题。
防范措施
第一步:定位注入源头
- 先排查反向代理配置:检查Nginx、Apache等前置反向代理的配置,是否存在
add_header $arg_*这类通配规则,这类规则会直接将所有查询参数作为响应头返回,是这类问题最常见的诱因 - 再排查应用内组件:遍历除当前过滤器外的所有全局拦截器、Servlet过滤器、
ResponseBodyAdvice实现类、框架全局头处理配置,排查是否有遍历request.getParameterMap()批量往响应头加内容的逻辑
- 先排查反向代理配置:检查Nginx、Apache等前置反向代理的配置,是否存在
第二步:配置响应头白名单校验(核心防护方案)
新增一个优先级最高的全局过滤器,对所有输出的响应头做白名单校验,仅允许业务需要的头返回,其余头全部移除,参考代码如下:
import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.List; public class SecureResponseHeaderFilter implements Filter { // 配置响应头白名单,仅允许业务需要的头返回 private static final List<String> ALLOWED_HEADERS = Arrays.asList( "content-type", "auth-token", "breadcrumbid", "cache-control", "expires", "pragma" ); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = new HeaderSafeHttpServletResponseWrapper((HttpServletResponse) response); chain.doFilter(request, res); } private static class HeaderSafeHttpServletResponseWrapper extends javax.servlet.http.HttpServletResponseWrapper { public HeaderSafeHttpServletResponseWrapper(HttpServletResponse response) { super(response); } @Override public void addHeader(String name, String value) { // 仅白名单内的头允许添加 if (ALLOWED_HEADERS.contains(name.toLowerCase())) { // 额外过滤换行符,防止头拆分注入 String safeValue = value.replaceAll("[\\r\\n]", ""); super.addHeader(name, safeValue); } } @Override public void setHeader(String name, String value) { if (ALLOWED_HEADERS.contains(name.toLowerCase())) { String safeValue = value.replaceAll("[\\r\\n]", ""); super.setHeader(name, safeValue); } } } }第三步:高危头特殊防护
针对
Location、Set-Cookie、Access-Control-Allow-Origin这类可能导致跳转、Cookie劫持、跨域绕过的高危响应头,即使加入白名单也不允许值来自用户可控的参数(查询参数、用户传入请求头、表单参数等),必须使用服务端硬编码值或者经过严格白名单校验的内容。第四步:POST请求参数限制
如果业务上POST接口不需要使用查询参数,可以在过滤器中增加校验:POST请求如果携带非空的queryString,直接返回400错误,从根源切断该类注入的传入路径。
内容的提问来源于stack exchange,提问作者user3458271
相关产品推荐
相关产品推荐

