zoukankan      html  css  js  c++  java
  • Spring-Security+Freemarker 开启跨域请求伪造防护功能

         CSRF简介——摘抄自《Spring实战(第4版)》

     我们可以回忆一下,当一个POST请求提交到“/spittles”上时,SpittleController将会为用户创建一个新的Spittle对象。但是,如果这个POST请求来源于其他站点的话,会怎么样呢?如果在其他站点提交如下表单,这个POST请求会造成什么样的结果呢?假设你禁不住获得一辆新汽车的诱惑,点击了按钮——那么你将会提交表单到如下地址http://www.spittr.com/spittles。如果你已经登录到了spittr.com,那么这就会广播一条消息,让每个人都知道你做了一件蠢事。这是跨站请求伪造(cross-site request forgery,CSRF)的一个简单样例。简单来讲,如果一个站点欺骗用户提交请求到其他服务器的话,就会发生CSRF攻击,这可能会带来消极的后果。尽管提交“I’m stupid!”这样的信息到微博站点算不上什么CSRF攻击的最糟糕场景,但是你可以很容易想到更为严重的攻击情景,它可能会对你的银行账号执行难以预期的操作。 

       从Spring Security 3.2开始,默认就会启用CSRF防护。实际上,除非你采取行为处理CSRF防护或者将这个功能禁用,否则的话,在应用中提交表单时,你可能会遇到问题。

       Spring Security通过一个同步token的方式来实现CSRF防护的功能。它将会拦截状态变化的请求(例如,非GET、HEAD、OPTIONS和TRACE的请求)并检查CSRF token。如果请求中不包含CSRF token的话,或者token不能与服务器端的token相匹配,请求将会失败,并抛出CsrfException异常。这意味着在你的应用中,所有的表单必须在一个“_csrf”域中提交token,而且这个token必须要与服务器端计算并存储的token一致,这样的话当表单提交的时候,才能进行匹配。

        好消息是,Spring Security已经简化了将token放到请求的属性中这一任务。

       一、Freemarker模板集成Spring Security-CSRF防止功能

                1.Spring Security配置防止CSRF为开启状态,默认情况下该功能是开启的,调用disable()方法可以禁止。

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        /**
         * HTTP请求处理
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            String doUrl = "/**/*.do";
            http
             .formLogin().loginPage("/user/login.do")
             .defaultSuccessUrl("/free/list.do")//启用FORM登录
            .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout","GET"))
            .and().authorizeRequests().antMatchers("/user/login.do").permitAll()//登录页允许所有人访问
            .and().portMapper().http(8898).mapsTo(8443)  //添加端口映射,做测试用
            .and().authorizeRequests().antMatchers(doUrl).authenticated()
            .and().requiresChannel().antMatchers("/free/**",doUrl).requiresSecure()
            .and().requiresChannel().antMatchers(doUrl).requiresInsecure()
            .and().httpBasic();
            //.and().csrf().disable();  //禁用CSRF
        }

              2.Freemarker模板绑定_csrf 值

    <#include "/templates/_base.ftl"/>
    <@layout;section>
    <#if section="title">  用户登录
    <#elseif section="css">
    <#elseif section="content">
    <div class="400px;height:300px;">
       <h3>用户登录</h3>
      <form name="f" action="/stest/user/login.do" method="POST">
        <input name="${_csrf.parameterName}" type="hidden" value="${_csrf.token}"> 
        <table>
            <tbody>
                <tr><td>User:</td><td><input type="text" name="username" value=""></td></tr>
                <tr><td>Password:</td><td><input type="password" name="password"></td></tr>
                <tr><td colspan="2"><input name="submit" type="submit" value="Login"></td></tr>
            </tbody>
        </table>
        <p>${msg!}</p>
    </form>
    </div>
    <#elseif section="scripts">
    </#if>
    </@layout>

          疑问解析:属性_csrf是怎么产生的呢? 根据调试发现,这个属性是在org.springframework.security.web.csrf.CsrfFilter过滤器中赋值到request的属性集合中的。因此可以在视图绑定过程中,直接获取。源码截图如下

                    3.查看登录页面输出的csrf-Token值,已经成功赋值。如果我们随便修改一下这个token值,然后post请求到服务端,会发现报403错误,请求被阻止。说明配置已经成功生效,防止了请求的伪造。

        

         

        

       二、当开启CSRF后,原来以Get方式,调用/logout,退出登录状态的功能失效了,跳转后报404错误。

             1、查看源码,发现框架方法里做了备注。大概意思就是开启CSRF后,logout方法需要以post方式提交。或者调用logoutRequestMatcher方法,显示设置/logout请求为GET方法

              

      2、用logoutRequestMatcher设置logout为get请求来解决404报错问题。POST方式比较简单这里就不在赘述。当然,实际项目中,最好选择以post方式退出系统。

    http
             .formLogin().loginPage("/user/login.do")
             .defaultSuccessUrl("/free/list.do")//启用FORM登录
            .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout","GET"))

          至此CSRF防止方案示例就讲完了。在项目中,对于post请求都需要注意提交_csrf到服务端。希望对你有所帮助,欢迎留言交流。

  • 相关阅读:
    NFC
    精品收藏:GitHub人工智能AI开源项目
    typedef的用法,C语言typedef详解
    “此人不存在”
    视频换脸-Deepfakes代码解读和训练说明
    Linux下__attribute__((visibility ("default")))的使用
    piao
    高通开源android源码下载
    iOpenWorskSDK下载和答疑贴
    解构领域驱动设计(三):领域驱动设计
  • 原文地址:https://www.cnblogs.com/MrSi/p/8006350.html
Copyright © 2011-2022 走看看