zoukankan      html  css  js  c++  java
  • SpringSecurity 中的 CSRF实现

    1. 基础知识##

    csrf就是诱导已登录过的用户在不知情的情况下,使用自己的登录凭据来完成一些不可告人之事。比如利用img标签或者script标签的src属性自动访问一些敏感api,或者是伪造一个form标签,action写的是一些敏感api,通过js自动提交表单等。

    1.1 防御手段###

    原则上修改功能的API,都要避免使用GET方式。然后就是两种防护手段,一个是校验referer,一个是csrftoken,前者用curl就能破,后者稍微麻烦一点点,也能破。虽然没法完美防御,但是网站这些基础功能还是要有,要不然漏扫都过不去。

    2. springboot中的实现##

    springboot是用的csrftoken值来实现的,就是每个post请求会生成一个token,这个值不在cookie里面,所以伪造没用,到时服务器端会进行比对,发现不一致就拒绝服务。
    弊端就是改造旧系统时要每个form都要改,ajax那种post的提交也需要写额外的函数获取token在放到所有请求里面,所以这个功能要提前规划,后面再改就比较麻烦了。

    和cors类似,也是用了一个filter,CsrfFilter来实现的过滤功能,底层结构是HttpSessionCsrfTokenRepository,提供了3个方法。

    CsrfFilter.java

        @Override
    	protected void doFilterInternal(HttpServletRequest request,
    			HttpServletResponse response, FilterChain filterChain)
    					throws ServletException, IOException {
    		request.setAttribute(HttpServletResponse.class.getName(), response);
                    //获取服务器保存的token
    		CsrfToken csrfToken = this.tokenRepository.loadToken(request);
    		final boolean missingToken = csrfToken == null;
                    //缺少token 重新生成并保存
    		if (missingToken) {
    			csrfToken = this.tokenRepository.generateToken(request);
    			this.tokenRepository.saveToken(csrfToken, request, response);
    		}
    		request.setAttribute(CsrfToken.class.getName(), csrfToken);
    		request.setAttribute(csrfToken.getParameterName(), csrfToken);
                    //如果url不匹配需要校验的csrf 就直接略过
    		if (!this.requireCsrfProtectionMatcher.matches(request)) {
    			filterChain.doFilter(request, response);
    			return;
    		}
                    //获得客户端token
    		String actualToken = request.getHeader(csrfToken.getHeaderName());
    		if (actualToken == null) {
    			actualToken = request.getParameter(csrfToken.getParameterName());
    		}
                    //token不匹配
    		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;
    		}
    
    		filterChain.doFilter(request, response);
    	}
    

    然后就是tokenRepository,基本都是使用LazyCsrfTokenRepository封装了HttpSessionCsrfTokenRepository。作用就是只有在实际取token时才会保存session,节省服务器资源,HttpSessionCsrfTokenRepository实现了CsrfTokenRepository接口定义三个关于token的方法

        CsrfToken generateToken(HttpServletRequest request);
    
        void saveToken(CsrfToken token, HttpServletRequest request,
    			HttpServletResponse response);
    
        CsrfToken loadToken(HttpServletRequest request);
    
    

    3. 如何开启csrf防御##

    csrf默认是开启的,配下忽略的url就可以了。

  • 相关阅读:
    [JAVA] 运行 java HelloWorld 命令,提示“错误: 找不到或无法加载主类
    「Ubuntu」 终端更新时,报错
    【MATLAB】 运行Simulink时出现报错
    Ubuntu提示boot内存不足
    python+unittest+requests实现接口自动化的方法
    Python + Requests + Unittest接口自动化测试实例分析
    七.测试执行的log读取
    五.DDT测试驱动
    操作json文件
    四.爬取拉勾网实例
  • 原文地址:https://www.cnblogs.com/june777/p/11996409.html
Copyright © 2011-2022 走看看