漏洞说明:通过篡改请求头中的Referer值依旧能够访问到接口。
通过http请求头里面的Referer随意访问接口
通过下面两个代码类程序来实现你的程序不会被攻击,里面有两个实体,如果你感觉这个程序对你有用,联系我,我私发你,代码就不做过多的解释,原理不难
package com.datalook.manage.filter;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @description:* @author: guoyunlong* @create: 2023-11-23 13:08**/
@Configuration
public class CsrfFilterConfig implements WebMvcConfigurer{@Beanpublic CsrfFilterInterceptor myCsrfInterceptor(){return new CsrfFilterInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {//这里可以添加多个拦截器registry.addInterceptor(myCsrfInterceptor()).addPathPatterns("/**")//img和resources为静态资源.excludePathPatterns("/img/**").excludePathPatterns("/images/**").excludePathPatterns("/resources/**").excludePathPatterns("/actuator/**").excludePathPatterns("/actuator/prometheus/**").excludePathPatterns("/permission/**");}@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/login").allowedOrigins("*").allowCredentials(true).allowedMethods("GET", "POST", "DELETE", "PUT").maxAge(3600);}}
package com.datalook.manage.filter;import com.datalook.util.common.ComponentProperties;
import com.datalook.util.common.StringUtils;
import com.datalook.util.log.LogUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @description:* @author: guoyunlong* @create: 2023-11-23 13:08**/
@Component
public class CsrfFilterInterceptor implements HandlerInterceptor {@Autowiredprivate ComponentProperties security;public boolean preHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object o) throws Exception {String referer = request.getHeader("Referer");String serverName = request.getServerName();//如果 referer 为空放行if (!StringUtils.hasText(referer)) {return true;}URL url = null;try {url = new URL(referer);} catch (MalformedURLException e) {httpServletResponse.setContentType("application/json; charset=UTF-8");httpServletResponse.getWriter().write("系统不支持当前域名的访问!");LogUtil.error("域名:{}解析异常", url);}referer = url.getHost();if (StringUtils.hasText(referer)) {// 不启用或者已忽略的domain不拦截if (!security.getCsrf().isEnable() || isExcludesDomain(referer)) {return true;}}// 判断是否存在外链请求本站if (StringUtils.hasText(referer) && referer.indexOf(serverName) < 0) {LogUtil.error("拦截到非法请求:=> 服务器域名:{} => 非法访问域名:{}", serverName, referer);httpServletResponse.setContentType("application/json; charset=UTF-8");httpServletResponse.getWriter().write("系统不支持当前域名的访问!");return false;} else {return true;}}/*** 判断是否为忽略的域名** @param urlPath URL路径* @return true-忽略,false-过滤*/private boolean isExcludesDomain(String urlPath) {if (security.getCsrf().getExcludesDomain() == null || security.getCsrf().getExcludesDomain().isEmpty()) {return false;}return security.getCsrf().getExcludesDomain().stream().map(pattern -> Pattern.compile("^" + pattern)).map(p -> p.matcher(urlPath)).anyMatch(Matcher::find);}
}
使用postman来测试修复后的结果,如果别人使用随意一个域名是可以访问你的接口或者页面的