springboot框架学习 springSecurity5的CSRF保护(cookie跨域保护)

昨天遇到的一个让我本人感觉是毁灭性的bug,出现的前提是我没有系统的了解springsecurity5这款安全框架,它封装管理的一些保护机制,其中导致我明明页面和对应的方法映射写的都好好的,结果就是从一个页面跳转另一个页面报出403错误,且显示得不到任何映射,这就很让我困扰,本来我以为是我controller层的方法写的有问题,做好如下的调试代码:

  @RequestMapping("query")
    public User query(String username){
        System.out.println("--------------------");
        User user = userService.queryByName(username);
        System.out.println("--------------------");
        return user;
    }

却发现人家压根就没有通过那个页面的表单访问这个映射或者说是直接被拒绝跳转网站操作。

这时候我就想到不是我代码的问题了,像这种拦截和屏蔽操作的无非就是字符编码过滤器,拦截器等具备链式过滤校对的安全性机制才能实现的了,我就想到了我为了实验添加进项目的安全框架springsecurity5框架结果我一查发现,果然!cookie跨域的问题。

然后我就查询关于cookie跨域或者是为什么cookie随着我前后端分离项目的运行会不同级别的改变?之前没有添加security框架时就不会有这个问题?原因很简单一般的浏览器不会对cookie跨域进行严格的限制,你自己写的本地端口服务你也不会设置cookie跨域的保护,但是如果是网络上大型网站的话,不设置跨域保护就会被不法分子攻击网站,窃取网站用户信息。

首先我们了解一下什么叫CSRF:见下图 

 如你所见,在没有登出webA的时候访问另一个应用webB浏览器就会带着A的cookie继续生成B的cookie这样的情况就会使得B回去访问A的时候cookie早就已经有了,能实现正常访问。这样的话如果你没有将cookie保存好点击网站某个广告,不小心让不法人员窃取你的cookie信息,他就可以利用你的用户去做一些操作等等。

怎么实现CSRF保护呢?就是不允许跨域访问,也可以不允许携带cookie访问。只要保证第一个网站的cookie信息不被第二个网站的cookie携带就可以。

SpringSecurity5帮我们实现了CSRF保护:(以下是springsecurity5对CSRF保护配置的源码)

public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<CsrfConfigurer<H>, H> {
    private CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(new HttpSessionCsrfTokenRepository());
    private RequestMatcher requireCsrfProtectionMatcher;
    private List<RequestMatcher> ignoredCsrfProtectionMatchers;
    private SessionAuthenticationStrategy sessionAuthenticationStrategy;
    private final ApplicationContext context;

    public CsrfConfigurer(ApplicationContext context) {
        this.requireCsrfProtectionMatcher = CsrfFilter.DEFAULT_CSRF_MATCHER;
        this.ignoredCsrfProtectionMatchers = new ArrayList();
        this.context = context;
    }

    public CsrfConfigurer<H> csrfTokenRepository(CsrfTokenRepository csrfTokenRepository) {
        Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
        this.csrfTokenRepository = csrfTokenRepository;
        return this;
    }

    public CsrfConfigurer<H> requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
        Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
        this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
        return this;
    }

    public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
        return ((CsrfConfigurer.IgnoreCsrfProtectionRegistry)(new CsrfConfigurer.IgnoreCsrfProtectionRegistry(this.context)).antMatchers(antPatterns)).and();
    }

    public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
        return ((CsrfConfigurer.IgnoreCsrfProtectionRegistry)(new CsrfConfigurer.IgnoreCsrfProtectionRegistry(this.context)).requestMatchers(requestMatchers)).and();
    }

    public CsrfConfigurer<H> sessionAuthenticationStrategy(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
        Assert.notNull(sessionAuthenticationStrategy, "sessionAuthenticationStrategy cannot be null");
        this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
        return this;
    }


        SessionManagementConfigurer<H> sessionConfigurer = (SessionManagementConfigurer)http.getConfigurer(SessionManagementConfigurer.class);
        if (sessionConfigurer != null) {
            sessionConfigurer.addSessionAuthenticationStrategy(this.getSessionAuthenticationStrategy());
        }

        filter = (CsrfFilter)this.postProcess(filter);
        http.addFilter(filter);
    }

    private RequestMatcher getRequireCsrfProtectionMatcher() {
        return (RequestMatcher)(this.ignoredCsrfProtectionMatchers.isEmpty() ? this.requireCsrfProtectionMatcher : new AndRequestMatcher(new RequestMatcher[]{this.requireCsrfProtectionMatcher, new NegatedRequestMatcher(new OrRequestMatcher(this.ignoredCsrfProtectionMatchers))}));
    }


我们可以发现它的保护其实更像是获取一些信息进行校验,目前我没打算把这源码都整明白,主要是理解这个跨域保护的机制就OK。

由于这个是自带的保护配置,我们可以通过添加一个标注有注解@Configuration且继承WebSecurityConfigurerAdapter类的一个配置类来改变这个保护机制的保护域。

配置类security_config:

Configuration
/*避免出现403报错,security具备的CSRF跨站访问保护比较强大,配置关闭*/
public class security_config extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        /*关闭csrf保护*/
        /*授权请求,任意请求,全部授权允许,登出全部允许,跨站访问全部允许*/
        http.authorizeRequests().anyRequest().permitAll().and().logout()
                .permitAll().and().csrf().disable();
    }
}

这样一个允许跨站登出的权限授权就可以了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ForestSpringH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值