spring security为我们默认提供了多种web攻击的防护

在 Spring Security 中提供了一个 HttpFirewall,看名字就知道这是一个请求防火墙,它可以自动处理掉一些非法请求。
image.png

一个是严格模式的防火墙设置,还有一个默认防火墙设置。
DefaultHttpFirewall 的限制相对于 StrictHttpFirewall 要宽松一些,当然也意味着安全性不如 StrictHttpFirewall。
Spring Security 中默认使用的是 StrictHttpFirewall。

配置

StrictHttpFirewall默认允许我们设置白名单,只有白名单中的请求才会被执行
image.png

从这段代码中我们看出来,你的 HTTP 请求方法必须是 DELETE、GET、HEAD、OPTIONS、PATCH、POST 以及 PUT 中的一个,请求才能发送成功,否则的话,就会抛出 RequestRejectedException 异常。

不校验请求方式

那如果你想发送其他 HTTP 请求方法,例如 TRACE ,该怎么办呢?我们只需要自己重新提供一个 StrictHttpFirewall 实例即可,如下:

  1. @Bean
  2. HttpFirewall httpFirewall() {
  3. StrictHttpFirewall firewall = new StrictHttpFirewall();
  4. firewall.setUnsafeAllowAnyHttpMethod(true);
  5. return firewall;
  6. }

其中,setUnsafeAllowAnyHttpMethod 方法表示不做 HTTP 请求方法校验,也就是什么方法都可以过。或者也可以通过 setAllowedHttpMethods 方法来重新定义可以通过的方法。

请求地址不能有分号

如果你使用了 Spring Security,请求地址是不能有 ; 【分号】的,如果请求地址有 ; 【分号】,就会自动跳转到如下页面:
image.png

什么时候请求地址中会包含 ; 呢?
在使用shiro的时候,如果你禁用了 Cookie,那么 jsessionid 就会出现在地址栏里,像下面这样:

  1. http://localhost:8080/hello;jsessionid=xx

这种传递 jsessionid 的方式实际上是非常不安全的,所以在 Spring Security 中,这种传参方式默认就禁用了
当然,如果你希望地址栏能够被允许出现 ; ,那么可以按照如下方式设置:

  1. @Bean
  2. HttpFirewall httpFirewall() {
  3. StrictHttpFirewall firewall = new StrictHttpFirewall();
  4. firewall.setAllowSemicolon(true);
  5. return firewall;
  6. }

「注意,在 URL 地址中,; 编码之后是 %3b 或者 %3B,所以地址中同样不能出现 %3b 或者 %3B」

注意:
自spring3.2之后,spring提供了一种新的传参方式
@MatrixVariable,该注解允许使用 ;【分号】进行传参的间隔
这种方式和spring security完全冲突,所以如果需要使用这种方法的话就需要额外配置security放行接口

例如:

@RequestMapping(value = "/hello/{id}")
public void hello(@PathVariable Integer id,@MatrixVariable String name) {
    System.out.println("id = " + id);
    System.out.println("name = " + name);
}

配置放行

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

请求

http://localhost:8080/hello/123;name=javaboy

结果

id = 123
name = javaboy

标准化URL

规定请求url必须是标准化的url
是否为标准化URL,需要从四个方面进行判断
image.png

  • getRequestURI 就是获取请求协议之外的字符;
  • getContextPath 是获取上下文路径,相当于是 project 的名字;
  • getServletPath 这个就是请求的 servlet 路径,
  • getPathInfo 则是除 contextPath 和 servletPath 之后剩余的部分

这四种路径中都不能包含如下字符

"./", "/../" or "/."

必须是可打印的AscII字符

如果请求包含不可打印的ASCII字符,则请求会被拒绝
image.png

双斜杠不被允许

如果请求地址中出现双斜杠,这个请求也将被拒绝。双斜杠 // 使用 URL 地址编码之后,是 %2F%2F,其中 F 大小写无所谓,所以请求地址中也能不出现 “%2f%2f”, “%2f%2F”, “%2F%2f”, “%2F%2F”。

如果你希望请求地址中可以出现 // ,可以按照如下方式配置:

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedDoubleSlash(true);
    return firewall;
}

% 不被允许

如果请求地址中出现 %,这个请求也将被拒绝。URL 编码后的 % 是 %25,所以 %25 也不能出现在 URL 地址中。
如果希望请求地址中可以出现 %,可以按照如下方式修改:

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedPercent(true);
    return firewall;
}

正反斜杠不被允许

如果请求地址中包含斜杠编码后的字符 %2F 或者 %2f ,则请求将被拒绝。
如果请求地址中包含反斜杠 \ 或者反斜杠编码后的字符 %5C 或者 %5c ,则请求将被拒绝。

如果希望去掉如上两条限制,可以按照如下方式来配置:

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowBackSlash(true);
    firewall.setAllowUrlEncodedSlash(true);
    return firewall;
}

.【点】 不被允许

如果请求地址中存在 . 编码之后的字符 %2e、%2E,则请求将被拒绝。
如需支持,按照如下方式进行配置:

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedPeriod(true);
    return firewall;
}

上面所说的这些限制,都是针对请求的 requestURI 进行的限制,而不是针对请求参数。例如你的请求格式是:

「注意:虽然我们可以手动修改 Spring Security 中的这些限制,但是不建议大家做任何修改,每一条限制都有它的原由,每放开一个限制,就会带来未知的安全风险。」