记一次解决CSRF的坑
漏洞扫描,需要解决csrf问题,先贴上代码,使用的是过滤器
package com.jdd.appim.web.filter;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* @author dataochen
* @Description 拦截请求 防止CSRF漏洞
* @date: 2019/9/6 14:26
*/
public class CsrfCheckFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(CsrfCheckFilter.class);
public CsrfCheckFilter(List<String> whiteHost) {
this.whiteHost = whiteHost;
}
public CsrfCheckFilter() {
}
/**
* 域名白名单
* 无需校验的
*/
private List<String> whiteHost = new ArrayList<String>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
LOGGER.info("####CsrfCheckFilter init");
// 把单点登录的加进白名单
try {
Properties props = new Properties();
props.load(CsrfCheckFilter.class.getResourceAsStream("/sso-client.properties"));
String property = props.getProperty("sso.server.host");
whiteHost.add(property);
LOGGER.info("###whiteHost=[{}]", JSONObject.toJSONString(whiteHost));
} catch (Exception e) {
LOGGER.error("###CsrfCheckFilter put sso host into white host exception,e={}", e);
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
String referer = req.getHeader("Referer");
String serverName = req.getServerName();
String scheme = req.getScheme();
LOGGER.debug("###CsrfCheckFilter doFilter referer={},serverName={}", referer, serverName);
LOGGER.debug("###CsrfCheckFilter doFilter scheme={}", scheme);
if (StringUtils.isNotBlank(referer)) {
// 判断是否是域名白名单中的域名
LOGGER.debug("###CsrfCheckFilter doFilter whiteHost={}", JSONObject.toJSONString(whiteHost));
if (!CollectionUtils.isEmpty(whiteHost)) {
for (String host : whiteHost) {
if (host.startsWith("http")) {
if (referer.startsWith(host)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
} else {
if (referer.startsWith("http://" + host) || referer.startsWith("https://" + host)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
}
}
// 判断是否是本系统的域名
if (!referer.startsWith(scheme + "://" + serverName)) {
throw new ServletException("System identified as cross-site request forgery, access denied");
}
}
filterChain.doFilter(servletRequest, servletResponse);
return;
}
@Override
public void destroy() {
}
}
本来这个过滤器没什么问题,后来项目改成了HTTPS访问应用,一直报静态资源找不到。后来经过排查,发现是这个过滤器的问题。在这个应用的上面有一层nginx反向代理,https请求到nginx后,nginx在转发时候,转发的是http,同时转发的响应头里面,多了一个refer,这个refer是https。因此问题就来了,在这个filter代码中,refer=https,scheme=http,因此代码执行到
if (!referer.startsWith(scheme + "://" + serverName)) 方法里面,扔出了一个servlet异常
还没有评论,来说两句吧...