温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

springboot中怎么利用security自定义CSRF防御

发布时间:2021-07-29 15:37:31 来源:亿速云 阅读:437 作者:Leah 栏目:大数据

今天就跟大家聊聊有关springboot中怎么利用security自定义CSRF防御,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

查看csrfFilter源码,会先去HttpSessionCsrfTokenRepository.loadToken加载CsrfToken ,其实就是从session中获取。

public CsrfToken loadToken(HttpServletRequest request) {     HttpSession session = request.getSession(false);     if (session == null) {         return null;     }     return (CsrfToken) session.getAttribute(this.sessionAttributeName); }

如果不存在,会创建一个CsrfToken 并放入session

public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {     if (token == null) {         HttpSession session = request.getSession(false);         if (session != null) {             session.removeAttribute(this.sessionAttributeName);         }     } else {         HttpSession session = request.getSession();         session.setAttribute(this.sessionAttributeName, token);     } }

之后会从request中取token,与从session中取出的token对比,所以这里开启csrf认证后,这四种请求是不验证csrf的”GET”, “HEAD”, “TRACE”, “OPTIONS”,常用的POST请求,每次都要么在请求头上加上X-CSRF-TOKEN:csrf值,或者在POST中加入参数_csrf:csrf值,这样才能取出request中的csrf和session中的对比。

    String actualToken = request.getHeader(csrfToken.getHeaderName());     if (actualToken == null) {         actualToken = request.getParameter(csrfToken.getParameterName());     }     if (!csrfToken.getToken().equals(actualToken)) {         if (this.logger.isDebugEnabled()) {             this.logger.debug("Invalid CSRF token found for "                     + UrlUtils.buildFullRequestUrl(request));         }         if (missingToken) {             this.accessDeniedHandler.handle(request, response,                     new MissingCsrfTokenException(actualToken));         }else {             this.accessDeniedHandler.handle(request, response,                     new InvalidCsrfTokenException(csrfToken, actualToken));         }         return;     }

如果request中取出的csrf和session中取出的不相等,会进入accessDeniedHandler.handle,这个accessDeniedHandler是AccessDeniedHandlerImpl,里面方法如下:

public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {     if(!response.isCommitted()) {       if(this.errorPage != null) {         request.setAttribute("SPRING_SECURITY_403_EXCEPTION", accessDeniedException);         response.setStatus(403);         RequestDispatcher dispatcher = request.getRequestDispatcher(this.errorPage);         dispatcher.forward(request, response);       } else {         response.sendError(403, accessDeniedException.getMessage());       }     } }

如果设置了errorPage会服务器内部转发到该路径,之后还是会经过security的各个filter进行登陆操作,最终登陆成功。这不是我要的,,所以需要自定义一个accessDeniedHandler。代码如下,如果不是登陆请求的 csrf不匹配,都退出当前用户,登陆用户不做csrf校验。

@Component public class CsrfAccessDeniedHandler implements AccessDeniedHandler {     private SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();     @Autowired     private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;     @Override     public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)	throws IOException, ServletException {         Authentication auth = SecurityContextHolder.getContext().getAuthentication();         logoutHandler.logout(request, response, auth);         ajaxLogoutSuccessHandler.onLogoutSuccess(request, response, auth);     } }

然后在securityConfig里配置

@Override protected void configure(HttpSecurity http) throws Exception {     // 允许iframe     http.headers().frameOptions().sameOrigin();     //登陆页面不做csrf校验     http.csrf().ignoringAntMatchers("/login");     //异常处理     http.exceptionHandling().         accessDeniedHandler(csrfAccessDeniedHandler) }

看完上述内容,你们对springboot中怎么利用security自定义CSRF防御有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI