昨天遇到的一个让我本人感觉是毁灭性的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> extends AbstractHttpConfigurer, H> {
private CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(new HttpSessionCsrfTokenRepository());
private RequestMatcher requireCsrfProtectionMatcher;
private List 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 csrfTokenRepository(CsrfTokenRepository csrfTokenRepository) {
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
this.csrfTokenRepository = csrfTokenRepository;
return this;
}
public CsrfConfigurer requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
return this;
}
public CsrfConfigurer ignoringAntMatchers(String... antPatterns) {
return ((CsrfConfigurer.IgnoreCsrfProtectionRegistry)(new CsrfConfigurer.IgnoreCsrfProtectionRegistry(this.context)).antMatchers(antPatterns)).and();
}
public CsrfConfigurer ignoringRequestMatchers(RequestMatcher... requestMatchers) {
return ((CsrfConfigurer.IgnoreCsrfProtectionRegistry)(new CsrfConfigurer.IgnoreCsrfProtectionRegistry(this.context)).requestMatchers(requestMatchers)).and();
}
public CsrfConfigurer sessionAuthenticationStrategy(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
Assert.notNull(sessionAuthenticationStrategy, "sessionAuthenticationStrategy cannot be null");
this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
return this;
}
SessionManagementConfigurer 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();
}
}
这样一个允许跨站登出的权限授权就可以了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)