spring security下开启csrf,同时支持session.invalidate()调用

来源:互联网 发布:淘宝店仓库如何管理 编辑:程序博客网 时间:2024/06/06 05:58

最近在做的一个java web项目,要求登录界面信息提交时使用https,登录成功后页面使用http,同时全站使用csrf防御。

然后https和http的访问会分别创建两个session,csrf的token存在于https创建的session中,当验证用户身份通过后,跳转到http进入时,新建的session中没有csrfToken,因此被403拒绝访问。

解决方法为:在身份验证成功后,跳转页面的action中加入

Cookie nck = new Cookie("JSESSIONID",request.getSession().getId());nck.setPath("/");nck.setSecure(true);response.addCookie(nck);
这样就可以保证跳转前后的session保持一致了。


但新的需求又来了:在某些action处理过程中,需要更新session id,可以参考《spring security 集成csrf与会话更新》,也可以修改spring security源码。

spring security的CsrfFilter.java文件中,在filterChain执行完回调后,再添加一次token到session中即可:

@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {CsrfToken csrfToken = tokenRepository.loadToken(request);final boolean missingToken = csrfToken == null;if (missingToken) {CsrfToken generatedToken = tokenRepository.generateToken(request);csrfToken = new SaveOnAccessCsrfToken(tokenRepository, request, response,generatedToken);}request.setAttribute(CsrfToken.class.getName(), csrfToken);request.setAttribute(csrfToken.getParameterName(), csrfToken);if (!requireCsrfProtectionMatcher.matches(request)) {filterChain.doFilter(request, response);//****以下是添加的代码****HttpSession session = request.getSession(false);if(session!=null){tokenRepository.saveToken(csrfToken, request, response);}//****以上是添加的代码****return;}System.out.println("method: "+request.getMethod()+" match.");String actualToken = request.getHeader(csrfToken.getHeaderName());if (actualToken == null) {System.out.println("req.getHeader.token==null");actualToken = request.getParameter(csrfToken.getParameterName());}if (!csrfToken.getToken().equals(actualToken)) {System.out.println("csrfToken:"+csrfToken.getToken());System.out.println("actualToken:"+actualToken);if (logger.isDebugEnabled()) {logger.debug("Invalid CSRF token found for "+ UrlUtils.buildFullRequestUrl(request));}if (missingToken) {accessDeniedHandler.handle(request, response,new MissingCsrfTokenException(actualToken));}else {accessDeniedHandler.handle(request, response,new InvalidCsrfTokenException(csrfToken, actualToken));}return;}System.out.println("csrf filter next doFilter");filterChain.doFilter(request, response);
****以下是添加的代码****HttpSession session = request.getSession(false);if(session!=null){tokenRepository.saveToken(csrfToken, request, response);}//****以上是添加的代码****return;
}

这样修改应该可行了,在运行中某些页面跳转时遇到session空指针问题,很纳闷,原来是jsp加载时,要获取session中的csrfToken,但是session为空,没搞懂原因,只能在HttpSessionCsrfTokenRepository.java的saveToken函数中添加session为空的判断:

public void saveToken(CsrfToken token, HttpServletRequest request,HttpServletResponse response) {if (token == null) {HttpSession session = request.getSession(false);if (session != null) {session.removeAttribute(sessionAttributeName);}}else {HttpSession session = request.getSession();if(session!=null)//在此处添加判断 session.setAttribute(sessionAttributeName, token);}}
修改完成后,再跑程序,就没问题了。






0 0