一:csrf漏洞原理
使用burp进行拦截请求 然后使用csrf伪造进行请求伪造。
二:csrf修复原理
在每个请求中增加referer字段,如果没有这个字段则说明是伪造的请求。然后判断referer字段的域名和request的请求域名是否相同,如果不同则说明是伪造的请求。
三:修复代码
本处判断只判断接口,对页面进行放行(判断是否为页面的依据是接口的controller和请求页面的controller的继承类不同,接口的集成的类是AbstractAPIController, 页面的集成类是 AbstractController,这两个类是自己写的。),
package com.newcapec.sd.pubauth.interceptor;
import com.newcapec.core.controller.AbstractAPIController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.MalformedURLException;
public class RefererInterceptor extends HandlerInterceptorAdapter {
private String[] refererDomain = new String[]{"www.baidu.com", "www.newcapec.com.cn"};
private String[] refererDomain_url = new String[]{"/sd-loginthird/third/ssologin", "/sd-open-platform", "/ueditor/imgUpload", "/sd-qxjgl", "/sd-oa", "/sd-oa-plus","/sd-loginthird/dingyong/callback","/sd-yxxt/register_face/v1"};
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
String referer = req.getHeader("referer");
String host = req.getServerName();
String req_url = req.getRequestURI();
if ("POST".equals(req.getMethod()) || "GET".equals(req.getMethod())) {
if (referer == null ) {
if ("GET".equals(req.getMethod())){
if(handler instanceof HandlerMethod){
HandlerMethod hm = (HandlerMethod) handler;
if(AbstractAPIController.class.isAssignableFrom(hm.getBean().getClass())){
if (refererDomain_url != null) {
for (String s : refererDomain_url) {
//访问的url在白名单中
if (req_url.contains(s)) {
return true;
}
}
}
// 状态置为404
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
return false;
}else{
return true;
}
}else{
return true;
}
} else {
if (refererDomain_url != null) {
for (String s : refererDomain_url) {
//访问的url在白名单中
if (req_url.contains(s)) {
return true;
}
}
}
// 状态置为404
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
return false;
}
}
java.net.URL url = null;
try {
url = new java.net.URL(referer);
} catch (MalformedURLException e) {
// URL解析异常,也置为404
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
return false;
}
// 首先判断请求域名和referer域名是否相同
if (!host.equals(url.getHost())) {
// 如果不等,判断是否在白名单中
if (refererDomain != null) {
for (String s : refererDomain) {
if (s.equals(url.getHost())) {
return true;
}
}
}
//20210907看看是否在白名单url中
if (refererDomain_url != null) {
for (String s : refererDomain_url) {
//访问的url在白名单中
if (s.equals(req_url)) {
return true;
}
}
}
return false;
}
}
return true;
}
}
除了这些还需要拦截器配置
package com.newcapec.sd.pubauth.interceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.newcapec.core.utils.StringUtils;
@Component
public class InterceptorConfiguration extends WebMvcConfigurerAdapter {
/** csrf请求白名单,在此白名单中的不进行拦截 */
@Value("${com.newcapec.login.interceptor.exclude:}")
private String exclude;
/**只要涉及到菜单查询,该值就不能为空*/
@Value("${com.newcapec.sd.default.systemcode:}")
public String systemcode;
/*是否开启 拦截器 ,默认 不开启 */
@Value("${newcapec.multi.login.limited:false}")
public boolean multiLoginLimited;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器
RefererInterceptor refererInterceptor = new RefererInterceptor();
// 设置是否进行拦截
refererInterceptor.setMultiLoginLimited(multiLoginLimited);
// Referer
InterceptorRegistration ir3 = registry.addInterceptor(refererInterceptor);
// 配置拦截的路径
ir3.addPathPatterns("/**");
if(StringUtils.hasText(exclude)){
String[] exs =exclude.split(",");
for(String e :exs){
if(StringUtils.notText(e)){
continue;
}
ir3.excludePathPatterns(e);
}
}
}
}