referer请求头实现防盗链

# 漏洞等级 中危 # 漏洞描述 防止盗连,比如我是个下载软件的网站,在下载页面我先用referer来判断上一页面是不是自己网站,如果不是,说明有人盗连了你的下载地址。 简单来说:Referer就是当前页面的上一页面,那么就可以根据Referer来判断你的页面是不是被盗取了,被另外一方的网站引用了。 # 修复代码 ## 配置类 ```java @Component @ConfigurationProperties (prefix = "referer") public class RefererProperties { // 白名单域名 private List<String> refererDomain; // 是否启用 private boolean enabled = false; public List<String> getRefererDomain() { return refererDomain; } public void setRefererDomain(List<String> refererDomain) { this.refererDomain = refererDomain; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ``` ## 过滤器 ```java import com.alibaba.fastjson.JSON; import com.uwit.bsdigistersystem.security.config.RefererProperties; import com.uwit.common.utils.ResultUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.MalformedURLException; @Component public class RefererFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(RefererFilter.class); @Autowired private RefererProperties properties; @Override public void init(FilterConfig filterConfig) { //空方法 } @Override public void destroy() { //空方法 } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse respose = (HttpServletResponse)servletResponse; if(!isPermittedRequest(request, respose)){ String referer = request.getHeader("referer"); String serverName = request.getServerName(); String url = request.getRequestURI(); logger.error("CSRF过滤器 => 服务器:{} => 当前域名:{},URL:{}", serverName, referer,url); String code = "404.001"; String message = "系统不支持当前域名的访问"; respose.setHeader("Cache-Control","no-cache"); respose.setCharacterEncoding("UTF-8"); respose.setContentType("application/json"); respose.getWriter().println(JSON.toJSONString(ResultUtil.error(code, message))); respose.getWriter().flush(); return; } chain.doFilter(request, respose); } public boolean isPermittedRequest(HttpServletRequest req, HttpServletResponse resp) { String referer = req.getHeader("referer"); String host = req.getServerName(); // 开启时做验证 if (properties.isEnabled()) { 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; } // 首先判断请求域名和referer域名是否相同 if (!host.equals(url.getHost())) { // 若是不等,判断是否在白名单中 if (properties.getRefererDomain() != null) { for (String s : properties.getRefererDomain()) { if (s.equals(url.getHost())) { return true; } } } return false; } } return true; } } ```