漏洞說明:通過篡改請求頭中的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來測試修復后的結果,如果別人使用隨意一個域名是可以訪問你的接口或者頁面的