zoukankan      html  css  js  c++  java
  • Spring-Security对CSRF攻击的支持

     何时使用CSRF保护
            什么时候应该使用CSRF保护?我们的建议是使用CSRF保护,可以通过浏览器处理普通用户的任何请求。如果你只是创建一个非浏览器客户端使用的服务,你可能会想要禁用CSRF保护。(即所有处理来自浏览器的请求需要是CSRF保护,如果后台服务是提供API调用那么可能就要禁用CSRF保护)

    配置CSRF保护

    CSRF保护默认情况下使用Java配置启用

    @EnableWebSecurity
    public class WebSecurityConfig extends
    WebSecurityConfigurerAdapter {
    
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http
    .csrf().disable();//禁用CSRF保护
    }
    }


    前提注意:SpringBoot实例中应用CSRF

    The URL that triggers log out to occur (default is /logout). If CSRF protection is enabled (default), then the request must also be a POST. For more information, please consult the JavaDoc.

    CSRF在SpringSecurity中默认是启动的,那么你的退出请求必须改为POST请求。这确保了注销需要CSRF令牌和一个恶意的用户不能强制注销用户

    所以在SpringSecurity中需要重新配置登出

    package com.niugang.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    
    
    @Configuration // 里面已经包含了@Component 所以不用再上下文中在引入入了
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // spring自带的
    @Autowired
    private UserDetailsService userDetailsService;
    
    
    /**
    * configure(HttpSecurity)方法定义了哪些URL路径应该被保护
    */
    @Override
    
    protected void configure(HttpSecurity http) throws Exception {
    
    
    http.authorizeRequests()// 该方法所返回的对象的方法来配置请求级别的安全细节
    .antMatchers("/login").permitAll() // 登录页面不拦截
    .antMatchers("/api/**").permitAll() //调用api不需要拦截
    .antMatchers(HttpMethod.POST, "/checkLogin").permitAll().anyRequest()
    .authenticated()// 对于登录路径不进行拦截
    .and().formLogin()// 配置登录页面
    .loginPage("/login")// 登录页面的访问路径;
    .loginProcessingUrl("/checkLogin")// 登录页面下表单提交的路径
    .failureUrl("/login?paramserror=true")// 登录失败后跳转的路径,为了给客户端提示
    .defaultSuccessUrl("/index")// 登录成功后默认跳转的路径;
    .and().logout()// 用户退出操作
    .logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))// 用户退出所访问的路径,需要使用Post方式
    .permitAll().logoutSuccessUrl("/login?logout=true")// 退出成功所访问的路径
    ;
    }
    
    /**
    * 忽略静态资源
    */
    
    
    @Override
    public void configure(WebSecurity web) throws Exception {
    /*
    * 在springboot中忽略静态文件路径,直接写静态文件的文件夹 springboot默认有静态文件的放置路径,如果应用spring
    * security,配置忽略路径 不应该从springboot默认的静态文件开始
    * 如:在本项目中,所有的js和css都放在static下,如果配置忽略路径,则不能以static开始
    * 配置成web.ignoring().antMatchers("/static/*");这样是不起作用的
    */
    
    
    web.ignoring().antMatchers("/themes/**", "/script/**");
    
    
    }
    
    
    /**
    * 配置自定义用户服务
    */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
    // .passwordEncoder(passwordEncoder());
    
    
    }
    
    
    /**
    * 密码加密
    */
    /*
    * @Bean public BCryptPasswordEncoder passwordEncoder() { return new
    * BCryptPasswordEncoder(); }
    */
    }
    
    
    HTML中需要以表单形式POST提交退出
    <form action="logout" method="post">
           <input type="hidden" name="${_csrf.parameterName}"
    value="${_csrf.token}" /> 
        <button type='submit' class='btn btn-warning' onclick="logout();">退出</button>
    </form>


    在登录页面输入用户名和密码,点击登录,页面报如下错误

    这就是页面在登录时没有向后台传入后台颁发的令牌,具体代码如下:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <link href="themes/bootstrap.min.css" rel="stylesheet" />
    <script type="text/javascript" src="script/jquery.min.js"></script>
    <!--layer弹出框-->
    <link rel="stylesheet" href="script/layer/mobile/need/layer.css">
    <script type="text/javascript" src="script/layer/layer.js"></script>
    </head>
    <!-- -->
    <style>
    form {
    width: 60%;
    margin: 0 auto;
    }
    </style>
    <body>
    <form action="checkLogin" method='post'>
    <h2 style="text-align: center">spring boot</h2>
    <div class="form-group">
    <label for="name">姓名</label> <input type="text" class="form-control"
    name="username" placeholder="姓名">
    </div>
    <div class="form-group">
    <label for="password">密码</label> <input type="password"
    class="form-control" name="password" placeholder="密码">
    </div>
             <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 
    <button type="submit" id="btn_save"
    class="btn btn-primary form-control">保存</button>
    </form>
    
    
    <script type="text/javascript">
       <#if errorMessage??> 
    layer.msg('${errorMessage}', {icon: 4,time:1000,anim: 6});
       
       </#if>
    
    </script>
    </body>
    </html>

    这样才能登录成功

    对于Ajax和JSON的异步请求

    <head>
    <meta charset="UTF-8">
    <meta name="_csrf" content="${_csrf.token}" />
    <!-- default header name is X-CSRF-TOKEN -->
    <meta name="_csrf_header" content="${_csrf.headerName}" />
    <title>Insert title here</title>
    <link rel="stylesheet" type="text/css" href="themes/bootstrap.min.css" />
    <script type="text/javascript" src="script/jquery.min.js"></script>
    <script type="text/javascript" src="script/bootstrap.js"></script>
    <!--layer弹出框-->
    <link rel="stylesheet" href="script/layer/mobile/need/layer.css">
    <script type="text/javascript" src="script/layer/layer.js"></script>
    <style type="text/css">
    button {
    margin-left: 15px;
    }
    </style>
    </head>

    每次在提交请求之前先设置header里面的token,这样才能正常运行

    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
    });

       用户想要坚持CSRF Token在cookie中。 默认情况下CookieCsrfTokenRepository将编写一个名为 XSRF-TOKEN的cookie和从头部命名 X-XSRF-TOKEN中读取或HTTP参数 _csrf。

    //代码如下:
    
    .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

    示例显式地设置cookieHttpOnly=false. 这是必要的,允许JavaScript(例如AngularJS)读取它。 如果你不需要使用JavaScript直接读取cookie的能力,建议省略 cookieHttpOnly=false (通过使用new CookieCsrfTokenRepository()代替) 提高安全性.

    The URL that triggers log out to occur (default is /logout). If CSRF protection is enabled (default), then the request must also be a POST. For more information, please consult the JavaDoc.

            

     微信公众号

     

     

  • 相关阅读:
    远程接入系统的问题
    FastReport
    通用FASTREPORT打印模块及接口方法
    cxGrid控件过滤筛选后如何获更新筛选后的数据集
    Oracle Data Integrator 12c (12.1.2)新特性
    ODI 12c 安装
    Kafka面试题
    Hadoop面试题
    Spark面试题
    JAVA面试题-数组字符串基础
  • 原文地址:https://www.cnblogs.com/niugang0920/p/12195976.html
Copyright © 2011-2022 走看看