spring-security中csrf防御原理

来源:互联网 发布:大闹天宫瑰羽7进8数据 编辑:程序博客网 时间:2024/06/06 15:39


..

    // 先从tokenRepository中加载token        CsrfToken csrfToken = tokenRepository.loadToken(request);        final boolean missingToken = csrfToken == null;        // 如果为空,则tokenRepository生成新的token,并保存到tokenRepository中        if(missingToken) {            CsrfToken generatedToken = tokenRepository.generateToken(request);            // 默认的SaveOnAccessCsrfToken方法,记录tokenRepository,            // tokenRepository,response,获取token时先将token同步保存到tokenRepository中            csrfToken = new SaveOnAccessCsrfToken(tokenRepository, request, response, generatedToken);        }        // 将token写入request的attribute中,方便页面上使用        request.setAttribute(CsrfToken.class.getName(), csrfToken);        request.setAttribute(csrfToken.getParameterName(), csrfToken);        // 如果不需要csrf验证的请求,则直接下传请求(requireCsrfProtectionMatcher是默认的对象,对符合^(GET|HEAD|TRACE|OPTIONS)$的请求不验证)        if(!requireCsrfProtectionMatcher.matches(request)) {            filterChain.doFilter(request, response);            return;        }        // 从用户请求中获取token信息        String actualToken = request.getHeader(csrfToken.getHeaderName());        if(actualToken == null) {            actualToken = request.getParameter(csrfToken.getParameterName());        }        // 验证,如果相同,则下传请求,如果不同,则抛出异常        if(!csrfToken.getToken().equals(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;        }        filterChain.doFilter(request, response);

使用样例

在web.xml中增加spring的过滤器代理
在spring的配置文件中增加过滤器
[html] view plain copy
  1. <bean id="csrfFilter" class="org.springframework.security.web.csrf.CsrfFilter">  
  2.     <constructor-arg>  
[html] view plain copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;"><!--</span><pre name="code" class="html">HttpSessionCsrfTokenRepository是把token放到session中来存取  
-->
[html] view plain copy
  1.         <bean class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository"/>  
  2.     </constructor-arg>  
  3. </bean>  
  4. <!-- 
  5.     如果用的是spring mvc 的form标签,则配置此项时自动将crsf的token放入到一个hidden的input中,而不需要开发人员显式的写入form 
  6. -->  
  7. <bean id="requestDataValueProcessor" class="org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor"/>  
如果配置了CsrfRequestDataValueProcessor,并且使用了spring的form标签来写表单代码,则这样就可以了。否则需要在页面上书写相关代码
首先获取token
[html] view plain copy
  1. <meta name="_csrf" content="${_csrf.token}"/>  
  2. <meta name="_csrf_header" content="${_csrf.headerName}"/>  
然后在发送请求之前将token放入header中(或者form表单中)
[javascript] view plain copy
  1. var token = $("meta[name='_csrf']").attr("content");  
  2. var header = $("meta[name='_csrf_header']").attr("content");  
  3. $(document).ajaxSend(function(e, xhr, options) {  
  4.     xhr.setRequestHeader(header, token);  
  5. });  

原创粉丝点击