Java应用安全扫描告警:HTTP头注入致外部服务交互,该如何处理?
回答:
需要添加Filter来校验Host和X-Forwarded-Host头,这是修复这类HTTP头注入引发的外部服务交互风险的直接有效方案,完全匹配安全扫描给出的整改建议。
具体操作可以按以下步骤来:
1. 定义安全FQDN白名单
先整理业务允许的合法域名列表,比如你的应用域名、信任的代理域名等,把这些作为白名单。可以硬编码在代码里(适合固定场景),或者放在配置文件中(方便动态更新):
private static final Set<String> ALLOWED_HOSTS = new HashSet<>(Arrays.asList( "your-app.com", "trusted-proxy.your-company.com", "api.your-app.com" ));
2. 实现校验Filter
根据你的应用类型选择对应的Filter实现:
普通Java Web应用(Servlet Filter)
public class HostValidationFilter implements Filter { private static final Set<String> ALLOWED_HOSTS = new HashSet<>(Arrays.asList( "your-app.com", "trusted-proxy.your-company.com" )); @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 校验Host头 String hostHeader = httpRequest.getHeader("Host"); if (!isValidHost(hostHeader)) { httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Host header"); return; } // 校验X-Forwarded-Host头(如果使用反向代理) String forwardedHostHeader = httpRequest.getHeader("X-Forwarded-Host"); if (forwardedHostHeader != null && !isValidHost(forwardedHostHeader)) { httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid X-Forwarded-Host header"); return; } chain.doFilter(request, response); } private boolean isValidHost(String host) { if (host == null || host.trim().isEmpty()) { return false; } // 去掉端口号(如果有的话),只校验域名部分 String hostWithoutPort = host.split(":")[0].toLowerCase(); return ALLOWED_HOSTS.contains(hostWithoutPort); } @Override public void destroy() {} }
然后在web.xml中配置Filter:
<filter> <filter-name>HostValidationFilter</filter-name> <filter-class>com.yourcompany.filter.HostValidationFilter</filter-class> </filter> <filter-mapping> <filter-name>HostValidationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Spring Boot应用(用OncePerRequestFilter)
如果是Spring Boot项目,推荐用OncePerRequestFilter,避免重复执行:
@Component public class HostValidationFilter extends OncePerRequestFilter { private static final Set<String> ALLOWED_HOSTS = new HashSet<>(Arrays.asList( "your-app.com", "trusted-proxy.your-company.com" )); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 校验Host头 String hostHeader = request.getHeader("Host"); if (!isValidHost(hostHeader)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Host header"); return; } // 校验X-Forwarded-Host头 String forwardedHost = request.getHeader("X-Forwarded-Host"); if (forwardedHost != null) { // 处理多个逗号分隔的Host值 String[] hosts = forwardedHost.split(","); for (String h : hosts) { String trimmedHost = h.trim(); if (!isValidHost(trimmedHost)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid X-Forwarded-Host header"); return; } } } filterChain.doFilter(request, response); } private boolean isValidHost(String host) { if (host == null || host.trim().isEmpty()) { return false; } String hostWithoutPort = host.split(":")[0].toLowerCase(); return ALLOWED_HOSTS.contains(hostWithoutPort); } }
3. 额外注意事项
- 如果你的应用部署在反向代理(如Nginx)之后,要确保只有代理服务器能设置X-Forwarded-Host头,禁止客户端直接发送这个头。比如在Nginx配置中覆盖该头的值,而不是传递客户端的:
proxy_set_header X-Forwarded-Host $host; - 白名单要根据业务实际情况定期更新,不要遗漏合法的域名,也不要包含不必要的域名。
- 除了头校验,还要确保应用中所有依赖外部服务的逻辑都做了输入验证,避免其他渠道的SSRF风险。
内容的提问来源于stack exchange,提问作者gene b.
相关产品推荐
相关产品推荐

