Spring REST 配置CSRF防御

Spring REST 配置CSRF防御

内容从如下几个方面展开

  • 什么是CSRF防御
  • 如何运用CSRF进行防护(WEB)
  • 如何将CSRF防护,运用到REST中 

1.什么是CSRF

CSRF 攻击简单来讲,是多Tab页面浏览器的一个安全漏洞,好比你正在访问A网站,此时若是浏览器有你的cookie,而且session没有过时,此时你去访问B网站,那么B网站能够直接调用A网站的接口,而A网站则认为是你本人进行的操做。如下是图示:java

2.如何进行防护

对CSRF进行防护,能够经过加Token.也就是当你访问A网站的时候,A会给你一个token,而后,接下去的post请求,你须要把token带上,否则服务器则拒绝接收这个请求。 
- 1. token的产生:spring-security 4.0以后默认开启csrf,能够直接产生csrf token。 
- 2. token的存储:这里存储是指服务端的存储,token是存储在session中。 
- 3. token的传送:token能够经过cookie,也能够放在header中自定义的属性中。 
- 4. token的接收和返回:前段收到http respon 以后,须要把相应的token返回回来。 
- 5. token校验:服务器端对本身持有的token和客户端反馈回来的token进行校验,决定是否拒绝服务(拒绝服务能够自定义)。web

3.REST 的CSRF防护

通常写REST服务(也就是直接@ResponseBody)返回json字符串,则能够把token加在header里头的自定义属性中,为何不能直接加在header中的cooike里,spring-sercurity官方给出的答案:spring

One might ask why the expected CsrfToken isn’t stored in a cookie by default. This is because there are known exploits in which headers (i.e. specify the cookies) can be set by another domain. This is the same reason Ruby on Rails no longer skips CSRF checks when the header X-Requested-With is present. See this webappsec.org thread for details on how to perform the exploit. Another disadvantage is that by removing the state (i.e. the timeout) you lose the ability to forcibly terminate the token if it is compromised.json

翻译一下: 
- 1.cookie能够被其余域设置 
- 2.cookie是没有状态的,可是若是是session(含有过时时间),则可使session过时,从而使token失效。(若有出入,欢迎拍砖)promise

既然如此,那么须要在header中加入token,咱们只要注册一个Filter,就能够完成这个功能: 
- STEP 1 建立Filter浏览器

/** * * "将CSRF TOKEN加入到header中" * * Created by hzlaojiaqi on 2016/9/13. */
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
    protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
    protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
        CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);

        if (token != null) {
            response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
            response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
            response.setHeader(RESPONSE_TOKEN_NAME , token.getToken());
        }

        filterChain.doFilter(request, response);
    }
}

 

  • STEP 2 加入到过滤器中安全

    @Configuration
    @EnableWebSecurity
    public class SecurityConfigure extends WebSecurityConfigurerAdapter {
    
    private static final Logger THIRDPARTY_LOG = LoggerFactory.getLogger("THIRDPARTY_LOGGER");
    
    @Autowired
    UserService userService;
    
    protected  void configure(HttpSecurity httpSecurity) throws Exception {
        CsrfTokenResponseHeaderBindingFilter csrfTokenFilter = new CsrfTokenResponseHeaderBindingFilter();
        CustomAccessDeniedHandler accessDeniedHandler=new CustomAccessDeniedHandler();
        httpSecurity.addFilterAfter(csrfTokenFilter,CsrfFilter.class);
    }
    }

实验

    1. 首先进行Get请求,获取header中CSRF的token(图片忘记保存了)
    1. 在header中加入token,发起post请求
    1. 不在header中加入token,发起post请求

状况2 带header发起token服务器

 
能够看到,服务器端正确返回数据。cookie

状况3 不带header发起tokensession

  能够看到,服务器端 拒绝了咱们的请求。

相关文章
相关标签/搜索