之前有朋友说,看SpringSecurity这么麻烦,不如自己写个Filter拦截请求,简单实用。当然自己写也可以实现,但是大多数情况下大家都不是专业的web安全工程师,所以要考虑的问题只有认证和授权。处理完这两个问题后,系统似乎就很安全了。其实不然!各种各样的web攻击每天都在发生,固定会话攻击,csrf攻击等等,如果你不了解这些攻击,那么你做出来的系统肯定无法防御这些攻击。使用SpringSecurity的好处是,即使你不了解这些攻击,也不必担心这些攻击,因为SpringSecurity已经为你做好了防御。我们常说SpringSecurity比Shiro更重量级,它有重量级的好处,比如功能全,安全管理更完善。使用SpringSecurity,您甚至不知道您的系统有多安全!今天就和大家聊一聊SpringSecurity自带的防火墙机制。好了,废话不多说,我们来看文章。1、HttpFirewall在SpringSecurity中提供了一个HttpFirewall。看名字就知道这是一个请求防火墙,可以自动处理一些非法请求。HttpFirewall目前有两个实现类:一个是严格模式防火墙设置,一个是默认防火墙设置。DefaultHttpFirewall的限制比StrictHttpFirewall宽松,这当然意味着安全性不如StrictHttpFirewall。StrictHttpFirewall在SpringSecurity中默认使用。2.保护措施那么StrictHttpFirewall是如何保护我们的应用程序的呢?让我们一一看看。2.1只允许白名单中的方法首先,对于请求的方法,只允许白名单中的方法,即不是所有的HTTP请求方法都可以执行。从StrictHttpFirewall的源码可以看出:添加(HttpMethod.GET.name());result.add(HttpMethod.HEAD.name());result.add(HttpMethod.OPTIONS.name());result.add(HttpMethod.PATCH.name());结果.add(HttpMethod.POST.name());result.add(HttpMethod.PUT.name());returnresult;}privatevoidrejectForbiddenHttpMethod(HttpServletRequestrequest){if(this.allowedHttpMethods==ALLOW_ANY_HTTP_METHOD){return;}if(!this.allowedHttpMethods.contains(request.getMethod())){thrownewRequestRejectedException("TherequestwasrejectedbecausetheHTTPmethod\""+request.getMethod()+"\"wasnotincludedwithinthewhitelist"+tthis.al}pthloweds};}从这段代码我们可以看出,你的HTTP请求方式一定是DELETE、GET、HEAD、OPTIONS、PATCH、POST、PUT其中之一,请求才能发送成功,否则会抛出RequestRejectedException。如果想发送其他的HTTP请求方式,比如TRACE,应该怎么办?我们只需要自己重新提供一个StrictHttpFirewall实例,如下:@BeanHttpFirewallhttpFirewall(){StrictHttpFirewallfirewall=newStrictHttpFirewall();firewall.setUnsafeAllowAnyHttpMethod(true);returnfirewall;}其中setUnsafeAllowAnyHttpMethod方法是指任何HTTP请求方法都可以得到验证。或者您也可以重新定义可以通过setAllowedHttpMethods方法传递的方法。2.2请求地址不能有分号。不知道你有没有试过。如果使用SpringSecurity,请求地址不能有;。如果请求地址有;,会自动跳转到如下页面:可以看到页面提示已经说了,因为你的请求地址包含;,所以请求失败。什么时候会;包含在请求地址中?不知道大家有没有注意到,在使用Shiro的时候,如果禁用cookie,地址栏会出现jsessionid,像这样:http://localhost:8080/hello;jsessionid=xx这种传递jsessionid的方法是其实很不安全(松哥会在下一篇文章和大家讨论这个问题),所以在SpringSecurity中,这种传递参数的方式默认为Disabled。当然,如果你想让地址栏出现;那么可以这样设置:@BeanHttpFirewallhttpFirewall(){StrictHttpFirewallfirewall=newStrictHttpFirewall();firewall.setAllowSemicolon(true);returnfirewall;}设置完成后,去访问同一个界面,可以看到虽然报错了这时候还是报错,错误是404,不是一开始的不允许的;这是错误的。注意在URL地址中,%3b或%3B之后;编码,因此%3b或%3B不能出现在地址中。有的小伙伴可能不知道或者没用过。从Spring3.2开始,带来了一种全新的传参方式@MatrixVariable。@MatrixVariable是Spring3.2自带的函数。该方法扩展了请求参数的传输格式,参数之间可以用;隔开。因为SpringSecurity默认禁止这种传递参数的方式,所以一般情况下,如果需要使用@MatrixVariable来标记参数,就得在SpringSecurity中额外释放。接下来,我将通过一个简单的例子向大家展示@MatrixVariable的用法。我们创建一个新的/hello方法:@RequestMapping(value="/hello/{id}")publicvoidhello(@PathVariableIntegerid,@MatrixVariableStringname){System.out.println("id="+id);System.out.println("name="+name);}另外,我们还需要配置SpringMVC,这样;不会被自动移除:@ConfigurationpublicclassWebMvcConfigextendsWebMvcConfigurationSupport{@OverrideprotectedvoidconfigurePathMatch(PathMatchConfigurerconfigurer){UrlPathHelperurlPathHelper=newUrlPathHelper();urlPathHelperem.lonerConerseRemt)setUrlPathHelper(urlPathHelper);}}然后允许启动URL也已配置到SpringSecurity注意项目(;),浏览器发送如下请求:http://localhost:8080/hello/123;name=javaboyconsole打印信息如下:id=123name=javaboy可以看到@MatrixVariable注解生效了。2.3必须是规范的URL请求地址必须是规范的URL。什么是标准化网址?标准化的URL主要从四个方面来判断。我们看源码:StrictHttpFirewall#isNormalized:privatestaticbooleanisNormalized(HttpServletRequestrequest){if(!isNormalized(request.getRequestURI())){returnfalse;}if(!isNormalized(request.getContextPath()){returnfalse;}if(!isNormalized(request.getServletPath())){returnfalse;}if(!isNormalized(request.getPathInfo())){returnfalse;}returntrue;}getRequestURI是获取请求协议以外的字符;getContextPath是获取上下文path,相当于项目名;getServletPath是请求的servlet路径,getPathInfo是去掉contextPath和servletPath后剩下的部分。这四个路径都不能包含如下字符串:"./","/../"or"/."2.4必须是可打印的ASCII字符如果请求地址包含不可打印的ASCII字符,请求将被拒绝,我们从源码中可以看出端倪:StrictHttpFirewall#containsOnlyPrintableAsciiCharactersprivatestaticbooleancontainsOnlyPrintableAsciiCharacters(Stringuri){intlength=uri.length();for(inti=0;i
