笔者最近碰到了一种需要针对某一域名跳过spring security csrf防御机制的问题,网上找了好久也没找到可行的办法,最后还是笔者自己针对细节的检查,找到了破局的办法,下面介绍一下具体的原理和实现方法
一、绕过csrf防御机制的原理
原理主要就是通过security自带的csrf可以配置对一些特定的uri不进行拦截,而这种配置可以使用/**进行对uri模糊匹配,这样就可以在特定域名的服务中给所有请求当前服务的uri加上一个特定的前缀,然后在当前服务的过滤器中对特定前缀的uri进行转发,将其转发到正确的uri上,就能绕过security自带的csrf拦截机制了。
二、具体实现
跨域调用的请求配置
//伪代码--主要是展示给uri添加前缀
HttpUtil.post(host + "/muyichen" + requestURI);
服务端csrf拦截白名单配置
// 该方法是继承自WebSecurityConfigurerAdapter类
@Override
protected void configure(HttpSecurity http) throws Exception {
// 开启csrf白名单配置
http.cors().and()
// 白名单
.csrf().ignoringAntMatchers("/muyichen/**");
}
过滤器中的转发方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String requestURI = request.getRequestURI();
String suffix = "/muyichen";
// 如果前缀是/muyichen,表明该请求为跨域请求,需要转发到正确的地址
if(suffix.equals(requestURI.substring(0, suffix.length()))) {
requestURI = requestURI.substring(suffix.length());
request.getRequestDispatcher(requestURI).forward(servletRequest, servletResponse);
return;
}
// 如果不是则跳过该过滤器
filterChain.doFilter(servletRequest, servletResponse);
}
三、需要注意的地方
- 1、转发过滤器最好是最后一个执行(如果没有特别配置的话,过滤器的执行顺序是按照首字母大小来排序的),因为这样不会影响之前的过滤逻辑(转发后请求不会再走过滤链了);
- 2、使用这个方法后,Controller头部中配置的action前缀需要注意不要和过滤器中的前缀相同,如果相同的话当前控制器中的所有接口都不会走csrf校验;