1. 跨站點請求偽造
風險:可能會竊取或操縱客戶會話和 cookie,它們可能用於模仿合法用戶,從而使黑客能夠以該用戶身份查看或變更用戶記錄以及執行事務。
原因:應用程序使用的認證方法不充分。
固定值:驗證“Referer”頭的值,並對每個提交的表單使用 one-time-nonce。
2. pom.xml添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
3. 配置文件添加配置
# 信息安全
security:
csrf:
enable: true
excludes:
4. 添加CSRF過濾器
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* CSRF過濾器
*
* @author CL
*
*/
@Slf4j
@Component
@ConfigurationProperties(prefix = "security.csrf")
@WebFilter(filterName = "CsrfFilter", urlPatterns = "/*")
public class CsrfFilter implements Filter {
/**
* 過濾器配置對象
*/
FilterConfig filterConfig = null;
/**
* 是否啟用
*/
private boolean enable;
public void setEnable(boolean enable) {
this.enable = enable;
}
/**
* 忽略的URL
*/
private List<String> excludes;
public void setExcludes(List<String> excludes) {
this.excludes = excludes;
}
/**
* 初始化
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
/**
* 攔截
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 不啟用或者已忽略的URL不攔截
if (!enable || isExcludeUrl(request.getServletPath())) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String referer = request.getHeader("Referer");
String serverName = request.getServerName();
// 判斷是否存在外鏈請求本站
if (null != referer && referer.indexOf(serverName) < 0) {
log.error("CSRF過濾器 => 服務器:{} => 當前域名:{}", serverName, referer);
servletResponse.setContentType("text/html; charset=utf-8");
servletResponse.getWriter().write("系統不支持當前域名的訪問!");
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
/**
* 銷毀
*/
@Override
public void destroy() {
this.filterConfig = null;
}
/**
* 判斷是否為忽略的URL
*
* @param urlPath URL路徑
* @return true-忽略,false-過濾
*/
private boolean isExcludeUrl(String url) {
if (excludes == null || excludes.isEmpty()) {
return false;
}
return excludes.stream().map(pattern -> Pattern.compile("^" + pattern)).map(p -> p.matcher(url))
.anyMatch(Matcher::find);
}
}