CSRF 就是跨域请求伪造,是一种常见的web攻击方式,解决思路也非常简单,主要是设置域名或路径白名单,对于未知的链接予以过滤,从而达到防护目的。
总共两个类,一个CSRFFilterConfigUtils防护配置工具类,主要作用是配置防护开关、请求路径白名单以及请求域名白名单;一个是CsrfFilter防护过滤类,该类实质是一个拦截器,拦截所有用户请求,匹配路径和域名,符合条件的通过,不符合条件的拦截掉;
以下为实际代码:
CSRFFilterConfigUtils 防护配置工具类
import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; / * @Auther: GMY * @Date: 2022/09/16/9:54 * @Description: CSRF防护配置工具类 */ @Component public class CSRFFilterConfigUtils { / * 跨站点请求路径白名单,通过英文逗号分隔。在application.properties配置 */ public static String csrfWhitePaths; / * 跨站点请求域名白名单,通过英文逗号分隔。在application.properties配置 */ public static String csrfWhiteDomains; / * csrf攻击防护开关配置 */ public static Boolean openCsrfProtect; / * @param * @return java.lang.Boolean * @author GMY * @date 2022/9/16 10:13 * @description csrf攻击防护开关配置,默认为开启 */ public static Boolean getOpenCsrfProtect() { return openCsrfProtect == null ? true : openCsrfProtect; } / * @param * @return java.lang.String[] * @author GMY * @date 2022/9/16 10:07 * @description 获取请求路径白名单 */ public static String[] getCsrfWhitePaths() { if (StringUtils.isNotEmpty(csrfWhitePaths)) { return csrfWhitePaths.split(","); } return null; } / * @param * @return java.lang.String[] * @author GMY * @date 2022/9/16 10:09 * @description 获取请求域名白名单 */ public static String[] getCsrfWhiteDomains() { if (StringUtils.isNotEmpty(csrfWhiteDomains)) { return csrfWhiteDomains.split(","); } return null; } @Value("${csrf.white.paths}") public static void setCsrfWhitePaths(String csrfWhitePaths) { CSRFFilterConfigUtils.csrfWhitePaths = csrfWhitePaths; } @Value("${csrf.white.domains}") public static void setCsrfWhiteDomains(String csrfWhiteDomains) { CSRFFilterConfigUtils.csrfWhiteDomains = csrfWhiteDomains; } @Value("${open.csrf.protect}") public void setOpenCsrfProtect(Boolean openCsrfProtect) { CSRFFilterConfigUtils.openCsrfProtect = openCsrfProtect; } }
讯享网
CsrfFilter 防护过滤类
讯享网import cn.hutool.json.JSONUtil; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URL; / * @Auther: GMY * @Date: 2022/09/15/19:54 * @Description: */ @WebFilter(urlPatterns = "/*",filterName = "csrfFilter") @Configuration public class CsrfFilter implements Filter { // 后台日志打印 private Logger log = LoggerFactory.getLogger(CsrfFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } / * @param servletRequest * @param servletResponse * @param filterChain * @return void * @author GMY * @date 2022/9/16 9:51 * @description 执行CRSF过滤操作 */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse res = (HttpServletResponse) servletResponse; // 判断CSRF防护是否开启,如果没开启则直接略过过滤操作 if (!CSRFFilterConfigUtils.getOpenCsrfProtect()) { filterChain.doFilter(servletRequest, servletResponse); } else { String referer = req.getHeader("Referer"); if (!StringUtils.isBlank(referer)) { // 获取Referer参数中的地址和端口 String refererHostAndPort = getHostAndPort(req,referer); // 获取RequestURL参数中的地址和端口 String requestHostAndPort = getHostAndPort(req,null); // 同域名和同端口,即同一个域的系统,通过 if (requestHostAndPort.equalsIgnoreCase(refererHostAndPort)) { filterChain.doFilter(servletRequest, servletResponse); }else { // 如果不同域名或端口,继续判断域名是否在白名单中,如果在白名单中则通过 if(isCsrfWhiteDomains(refererHostAndPort)) { filterChain.doFilter(servletRequest, servletResponse); return; } // 获取RequestURL参数中的路径信息 String path = new URL(req.getRequestURL().toString()).getPath(); log.info("request请求路径 path = " + path); // 将路径中的域名去除,只保留具体路径 String actionPath = path.replaceAll(servletRequest.getServletContext().getContextPath(), ""); // 判断路径是否在访问路径白名单中,如果在白名单中,则通过,继续后续执行 if(isCsrfWhitePaths(actionPath)) { filterChain.doFilter(servletRequest, servletResponse); return; } log.warn("csrf跨站点伪造请求已经被拦截:"); log.warn("requestURL = " + req.getRequestURL().toString()); log.warn("referer = " + referer); res.sendRedirect(req.getContextPath() + "/illegal"); return; } }else{ filterChain.doFilter(servletRequest, servletResponse); } } } / * @param request * @param referer * @return java.lang.String * @author GMY * @date 2022/9/16 9:34 * @description 获取请求地址和端口 */ protected String getHostAndPort(HttpServletRequest request, String referer) throws IOException { URL url; if (StringUtils.isNotEmpty(referer)) { url = new URL(referer); } else { url = new URL(request.getRequestURL().toString()); } String requestHostAndPort; if(url.getPort() == -1) { requestHostAndPort = url.getHost(); }else { requestHostAndPort = url.getHost() + ":" + url.getPort(); } return requestHostAndPort; } @Override public void destroy() { } / * @param path * @return boolean * @author GMY * @date 2022/9/16 9:52 * @description 判断请求路径是否在路径白名单中 */ private boolean isCsrfWhitePaths(String path) { if(CSRFFilterConfigUtils.getCsrfWhitePaths() != null && CSRFFilterConfigUtils.getCsrfWhitePaths().length > 0) { for (String csrfWhitePath : CSRFFilterConfigUtils.getCsrfWhitePaths()) { if(!StringUtils.isBlank(csrfWhitePath)) { if(csrfWhitePath.equals(path)) { log.info("跨站点请求所有路径白名单:csrfWhitePaths = " + JSONUtil.toJsonStr(CSRFFilterConfigUtils.getCsrfWhitePaths())); log.info("符合跨站点请求路径白名单:path = " + path); return true; } } } } return false; } / * @param refererHostAndPort * @return boolean * @author GMY * @date 2022/9/16 9:52 * @description 判断请求域名是否在域名白名单中 */ private boolean isCsrfWhiteDomains(String refererHostAndPort) { if(CSRFFilterConfigUtils.getCsrfWhiteDomains() != null && CSRFFilterConfigUtils.getCsrfWhiteDomains().length > 0) { for (String csrfWhiteDomain : CSRFFilterConfigUtils.getCsrfWhiteDomains()) { if(!StringUtils.isBlank(csrfWhiteDomain)) { if(csrfWhiteDomain.equals(refererHostAndPort)) { log.info("跨站点请求所有【域名】]白名单:csrfWhiteDomains = " + JSONUtil.toJsonStr(CSRFFilterConfigUtils.getCsrfWhiteDomains())); log.info("符合跨站点请求【域名】白名单:refererHost = " + refererHostAndPort); return true; } } } log.info("跨站点请求非法【域名】:refererHost = " + refererHostAndPort); } return false; } }
以上代码仅供学习交流使用,代码中涉及到真实项目信息的内容我都做了相应修改

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/48578.html