日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
SpringSecurity系列之請(qǐng)求防火墻默認(rèn)已開(kāi)啟

之前有小伙伴表示,看 Spring Security 這么麻煩,不如自己寫(xiě)一個(gè) Filter 攔截請(qǐng)求,簡(jiǎn)單實(shí)用。

十多年的哈巴河網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)營(yíng)銷(xiāo)推廣的優(yōu)勢(shì)是能夠根據(jù)用戶(hù)設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整哈巴河建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“哈巴河網(wǎng)站設(shè)計(jì)”,“哈巴河網(wǎng)站推廣”以來(lái),每個(gè)客戶(hù)項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

自己寫(xiě)當(dāng)然也可以實(shí)現(xiàn),但是大部分情況下,大家都不是專(zhuān)業(yè)的 Web 安全工程師,所以考慮問(wèn)題也不過(guò)就是認(rèn)證和授權(quán),這兩個(gè)問(wèn)題處理好了,似乎系統(tǒng)就很安全了。

其實(shí)不是這樣的!

各種各樣的 Web 攻擊每天都在發(fā)生,什么固定會(huì)話(huà)攻擊、csrf 攻擊等等,如果不了解這些攻擊,那么做出來(lái)的系統(tǒng)肯定也不能防御這些攻擊。

使用 Spring Security 的好處就是,即使不了解這些攻擊,也不用擔(dān)心這些攻擊,因?yàn)?Spring Security 已經(jīng)幫你做好防御工作了。

我們常說(shuō)相比于 Shiro,Spring Security 更加重量級(jí),重量級(jí)有重量級(jí)的好處,比如功能全,安全管理更加完備。用了 Spring Security,你都不知道自己的系統(tǒng)有多安全!

今天我就來(lái)和大家聊一聊 Spring Security 中自帶的防火墻機(jī)制。

好了,不廢話(huà)了,我們來(lái)看文章。

1.HttpFirewall

在 Spring Security 中提供了一個(gè) HttpFirewall,看名字就知道這是一個(gè)請(qǐng)求防火墻,它可以自動(dòng)處理掉一些非法請(qǐng)求。

HttpFirewall 目前一共有兩個(gè)實(shí)現(xiàn)類(lèi):

一個(gè)是嚴(yán)格模式的防火墻設(shè)置,還有一個(gè)默認(rèn)防火墻設(shè)置。

DefaultHttpFirewall 的限制相對(duì)于 StrictHttpFirewall 要寬松一些,當(dāng)然也意味著安全性不如 StrictHttpFirewall。

Spring Security 中默認(rèn)使用的是 StrictHttpFirewall。

2.防護(hù)措施

那么 StrictHttpFirewall 都是從哪些方面來(lái)保護(hù)我們的應(yīng)用呢?我們來(lái)挨個(gè)看下。

2.1 只允許白名單中的方法

首先,對(duì)于請(qǐng)求的方法,只允許白名單中的方法,也就是說(shuō),不是所有的 HTTP 請(qǐng)求方法都可以執(zhí)行。

這點(diǎn)我們可以從 StrictHttpFirewall 的源碼中看出來(lái):

 
 
 
  1. public class StrictHttpFirewall implements HttpFirewall { 
  2.  private Set allowedHttpMethods = createDefaultAllowedHttpMethods(); 
  3.  private static Set createDefaultAllowedHttpMethods() { 
  4.   Set result = new HashSet<>(); 
  5.   result.add(HttpMethod.DELETE.name()); 
  6.   result.add(HttpMethod.GET.name()); 
  7.   result.add(HttpMethod.HEAD.name()); 
  8.   result.add(HttpMethod.OPTIONS.name()); 
  9.   result.add(HttpMethod.PATCH.name()); 
  10.   result.add(HttpMethod.POST.name()); 
  11.   result.add(HttpMethod.PUT.name()); 
  12.   return result; 
  13.  } 
  14.  private void rejectForbiddenHttpMethod(HttpServletRequest request) { 
  15.   if (this.allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) { 
  16.    return; 
  17.   } 
  18.   if (!this.allowedHttpMethods.contains(request.getMethod())) { 
  19.    throw new RequestRejectedException("The request was rejected because the HTTP method \"" + 
  20.      request.getMethod() + 
  21.      "\" was not included within the whitelist " + 
  22.      this.allowedHttpMethods); 
  23.   } 
  24.  } 

從這段代碼中我們看出來(lái),你的 HTTP 請(qǐng)求方法必須是 DELETE、GET、HEAD、OPTIONS、PATCH、POST 以及 PUT 中的一個(gè),請(qǐng)求才能發(fā)送成功,否則的話(huà),就會(huì)拋出 RequestRejectedException 異常。

那如果你想發(fā)送其他 HTTP 請(qǐng)求方法,例如 TRACE ,該怎么辦呢?我們只需要自己重新提供一個(gè) StrictHttpFirewall 實(shí)例即可,如下:

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

其中,setUnsafeAllowAnyHttpMethod 方法表示不做 HTTP 請(qǐng)求方法校驗(yàn),也就是什么方法都可以過(guò)?;蛘咭部梢酝ㄟ^(guò) setAllowedHttpMethods 方法來(lái)重新定義可以通過(guò)的方法。

2.2 請(qǐng)求地址不能有分號(hào)

不知掉大家有沒(méi)有試過(guò),如果你使用了 Spring Security,請(qǐng)求地址是不能有 ; 的,如果請(qǐng)求地址有 ; ,就會(huì)自動(dòng)跳轉(zhuǎn)到如下頁(yè)面:

可以看到,頁(yè)面的提示中已經(jīng)說(shuō)了,因?yàn)槟愕恼?qǐng)求地址中包含 ;,所以請(qǐng)求失敗。

什么時(shí)候請(qǐng)求地址中會(huì)包含 ; 呢?不知道小伙伴們?cè)谑褂?Shiro 的時(shí)候,有沒(méi)有注意到,如果你禁用了 Cookie,那么 jsessionid 就會(huì)出現(xiàn)在地址欄里,像下面這樣:

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

這種傳遞 jsessionid 的方式實(shí)際上是非常不安全的(松哥后面的文章會(huì)和大家細(xì)聊這個(gè)問(wèn)題),所以在 Spring Security 中,這種傳參方式默認(rèn)就禁用了。

當(dāng)然,如果你希望地址欄能夠被允許出現(xiàn) ; ,那么可以按照如下方式設(shè)置:

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

設(shè)置完成之后,再去訪(fǎng)問(wèn)相同的接口,可以看到,此時(shí)雖然還是報(bào)錯(cuò),但是錯(cuò)誤是 404 了,而不是一開(kāi)始那個(gè)不允許 ; 的錯(cuò)了。

注意,在 URL 地址中,; 編碼之后是 %3b 或者 %3B,所以地址中同樣不能出現(xiàn) %3b 或者 %3B

題外話(huà)

有的小伙伴可能不知道或者沒(méi)用過(guò),Spring3.2 開(kāi)始,帶來(lái)了一種全新的傳參方式 @MatrixVariable。

@MatrixVariable 是 Spring3.2 中帶來(lái)的功能,這種方式拓展了請(qǐng)求參數(shù)的傳遞格式,使得參數(shù)之間可以用 ; 隔開(kāi),這種傳參方式真是哪壺不開(kāi)提哪壺。因?yàn)?Spring Security 默認(rèn)就是禁止這種傳參方式,所以一般情況下,如果你需要使用 @MatrixVariable 來(lái)標(biāo)記參數(shù),就得在 Spring Security 中額外放行。

接下來(lái)我通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)和大家演示一下 @MatrixVariable 的用法。

我們新建一個(gè) /hello 方法:

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

另外我們還需要配置一下 SpringMVC,使 ; 不要被自動(dòng)移除了:

 
 
 
  1. @Configuration 
  2. public class WebMvcConfig extends WebMvcConfigurationSupport { 
  3.     @Override 
  4.     protected void configurePathMatch(PathMatchConfigurer configurer) { 
  5.         UrlPathHelper urlPathHelper = new UrlPathHelper(); 
  6.         urlPathHelper.setRemoveSemicolonContent(false); 
  7.         configurer.setUrlPathHelper(urlPathHelper); 
  8.     } 

然后啟動(dòng)項(xiàng)目(注意,Spring Security 中也已經(jīng)配置了允許 URL 中存在 ;),瀏覽器發(fā)送如下請(qǐng)求:

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

控制臺(tái)打印信息如下:

 
 
 
  1. id = 123 
  2. name = javaboy 

可以看到,@MatrixVariable 注解已經(jīng)生效了。

2.3 必須是標(biāo)準(zhǔn)化 URL

請(qǐng)求地址必須是標(biāo)準(zhǔn)化 URL。

什么是標(biāo)準(zhǔn)化 URL?標(biāo)準(zhǔn)化 URL 主要從四個(gè)方面來(lái)判斷,我們來(lái)看下源碼:

StrictHttpFirewall#isNormalized:

 
 
 
  1. private static boolean isNormalized(HttpServletRequest request) { 
  2.  if (!isNormalized(request.getRequestURI())) { 
  3.   return false; 
  4.  } 
  5.  if (!isNormalized(request.getContextPath())) { 
  6.   return false; 
  7.  } 
  8.  if (!isNormalized(request.getServletPath())) { 
  9.   return false; 
  10.  } 
  11.  if (!isNormalized(request.getPathInfo())) { 
  12.   return false; 
  13.  } 
  14.  return true; 

getRequestURI 就是獲取請(qǐng)求協(xié)議之外的字符;getContextPath 是獲取上下文路徑,相當(dāng)于是 project 的名字;getServletPath 這個(gè)就是請(qǐng)求的 servlet 路徑,getPathInfo 則是除過(guò) contextPath 和 servletPath 之后剩余的部分。

這四種路徑中,都不能包含如下字符串:

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

2.4 必須是可打印的 ASCII 字符

如果請(qǐng)求地址中包含不可打印的 ASCII 字符,請(qǐng)求則會(huì)被拒絕,我們可以從源碼中看出端倪:

StrictHttpFirewall#containsOnlyPrintableAsciiCharacters

 
 
 
  1. private static boolean containsOnlyPrintableAsciiCharacters(String uri) { 
  2.  int length = uri.length(); 
  3.  for (int i = 0; i < length; i++) { 
  4.   char c = uri.charAt(i); 
  5.   if (c < '\u0020' || c > '\u007e') { 
  6.    return false; 
  7.   } 
  8.  } 
  9.  return true; 

2.5 雙斜杠不被允許

如果請(qǐng)求地址中出現(xiàn)雙斜杠,這個(gè)請(qǐng)求也將被拒絕。雙斜杠 // 使用 URL 地址編碼之后,是 %2F%2F,其中 F 大小寫(xiě)無(wú)所謂,所以請(qǐng)求地址中也能不出現(xiàn) "%2f%2f", "%2f%2F", "%2F%2f", "%2F%2F"。

如果你希望請(qǐng)求地址中可以出現(xiàn) // ,可以按照如下方式配置:

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

2.6 % 不被允許

如果請(qǐng)求地址中出現(xiàn) %,這個(gè)請(qǐng)求也將被拒絕。URL 編碼后的 % 是 %25,所以 %25 也不能出現(xiàn)在 URL 地址中。

如果希望請(qǐng)求地址中可以出現(xiàn) %,可以按照如下方式修改:

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

2.7 正反斜杠不被允許

如果請(qǐng)求地址中包含斜杠編碼后的字符 %2F 或者 %2f ,則請(qǐng)求將被拒絕。

如果請(qǐng)求地址中包含反斜杠 \ 或者反斜杠編碼后的字符 %5C 或者 %5c ,則請(qǐng)求將被拒絕。

如果希望去掉如上兩條限制,可以按照如下方式來(lái)配置:

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

2.8 . 不被允許

如果請(qǐng)求地址中存在 . 編碼之后的字符 %2e、%2E,則請(qǐng)求將被拒絕。

如需支持,按照如下方式進(jìn)行配置:

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

2.9 小結(jié)

需要強(qiáng)調(diào)一點(diǎn),上面所說(shuō)的這些限制,都是針對(duì)請(qǐng)求的 requestURI 進(jìn)行的限制,而不是針對(duì)請(qǐng)求參數(shù)。例如你的請(qǐng)求格式是:

 
 
 
  1. http://localhost:8080/hello?param=aa%2ebb 

那么 2.7 小節(jié)說(shuō)的限制和你沒(méi)關(guān)系。

這個(gè)大家從 StrictHttpFirewall 源碼中很容易看到:

 
 
 
  1. public class StrictHttpFirewall implements HttpFirewall { 
  2.  @Override 
  3.  public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException { 
  4.   rejectForbiddenHttpMethod(request); 
  5.   rejectedBlacklistedUrls(request); 
  6.   rejectedUntrustedHosts(request); 
  7.  
  8.   if (!isNormalized(request)) { 
  9.    throw new RequestRejectedException("The request was rejected because the URL was not normalized."); 
  10.   } 
  11.  
  12.   String requestUri = request.getRequestURI(); 
  13.   if (!containsOnlyPrintableAsciiCharacters(requestUri)) { 
  14.    throw new RequestRejectedException("The requestURI was rejected because it can only contain printable ASCII characters."); 
  15.   } 
  16.   return new FirewalledRequest(request) { 
  17.    @Override 
  18.    public void reset() { 
  19.    } 
  20.   }; 
  21.  } 
  22.  private void rejectedBlacklistedUrls(HttpServletRequest request) { 
  23.   for (String forbidden : this.encodedUrlBlacklist) { 
  24.    if (encodedUrlContains(request, forbidden)) { 
  25.     throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\""); 
  26.    } 
  27.   } 
  28.   for (String forbidden : this.decodedUrlBlacklist) { 
  29.    if (decodedUrlContains(request, forbidden)) { 
  30.     throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\""); 
  31.    } 
  32.   } 
  33.  } 
  34.  private static boolean encodedUrlContains(HttpServletRequest request, String value) { 
  35.   if (valueContains(request.getContextPath(), value)) { 
  36.    return true; 
  37.   } 
  38.   return valueContains(request.getRequestURI(), value); 
  39.  } 
  40.  
  41.  private static boolean decodedUrlContains(HttpServletRequest request, String value) { 
  42.   if (valueContains(request.getServletPath(), value)) { 
  43.    return true; 
  44.   } 
  45.   if (valueContains(request.getPathInfo(), value)) { 
  46.    return true; 
  47.   } 
  48.   return false; 
  49.  } 
  50.  private static boolean valueContains(String value, String contains) { 
  51.   return value != null && value.contains(contains); 
  52.  } 

rejectedBlacklistedUrls 方法就是校驗(yàn) URL 的,該方法邏輯很簡(jiǎn)單,我就不再贅述了。

注意:雖然我們可以手動(dòng)修改 Spring Security 中的這些限制,但是松哥不建議大家做任何修改,每一條限制都有它的原由,每放開(kāi)一個(gè)限制,就會(huì)帶來(lái)未知的安全風(fēng)險(xiǎn)。后面松哥在和大家分享 Web 中的安全攻擊時(shí),也會(huì)再次提到這些限制的作用,請(qǐng)小伙伴們保持關(guān)注哦。

3.總結(jié)

沒(méi)想到吧?Spring Security 竟然為你做了這么多事情!正好應(yīng)了那句雞湯:你所謂的歲月靜好,不過(guò)是有人在替你負(fù)重前行。


當(dāng)前標(biāo)題:SpringSecurity系列之請(qǐng)求防火墻默認(rèn)已開(kāi)啟
文章出自:http://www.5511xx.com/article/ccehhei.html