漏洞描述
漏洞描述:
跨站请求伪造(Cross-site request forgery,简称CSRF),是一种常见的Web安全漏洞,由于在Web请求中重要操作的所有参数可被猜测到,攻击者可通过一些技术手段欺骗用户的浏览器去访问一个用户曾经认证过的网站,遂使攻击者可冒用用户的身份,进行恶意操作。
经测试,服务器未校验Referer头,因此攻击者可以直接构造一个恶意的访问地址让用户在不知情的情况下访问从而实现CSRF恶意操作。
解决建议
解决建议:
增加拦截器,判断referer是否合法,合法则放行。
给出的例子,springboot的配置
referer:
# 是否开启referer拦截
enabled: true
# 拦截referer白名单
refererDomain:
- localhost
- 127.0.0.1
读取springboot配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "referer")
@Data
public class RefererProperties {
private Boolean enabled = false;
// 白名单域名
private List<String> refererDomain;
}
referer拦截器
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.MalformedURLException;
@Component
@Slf4j
public class RefererInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RefererProperties refererProperties;
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
//是否开启referer拦截器
if(!refererProperties.getEnabled()){
return true;
}
String referer = req.getHeader("referer");
String host = req.getServerName();
// 若无referer,放行
if (referer == null) {
return true;
}
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;
}
String refererUrl = url.getHost();
// 首先判断请求域名和referer域名是否相同
if (!host.equals(refererUrl)) {
// 若是不等,判断是否在白名单中
log.info("RefererInterceptorConfig-->\nrefererUrl:{}\nhost:{}\nrefererProperties:{}", refererUrl, host, refererProperties);
if (refererProperties.getRefererDomain() != null) {
for (String s : refererProperties.getRefererDomain()) {
if (s.equals(refererUrl)) {
return true;
}
}
}
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
return false;
}
return true;
}
}
配置拦截器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* referer拦截器注册
*/
@EnableWebMvc
@Configuration
public class RefererInterceptorConfig extends WebMvcConfigurerAdapter {
@Autowired
private RefererInterceptor refererInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(refererInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
方法说明:
方法: referer.enabled = true/false 方便开启/关闭拦截器逻辑
方法: referer.refererDomain 配置白名单域名列表
小编这暂且优化成这样,有更好的方法,欢迎留言噢。