Java安全 - Spring Web MVC 请求解析过程
前言
主要是有师傅对一些鉴权的Spring不太懂,并且自身也有不太清楚的地方于是跟下 Spring Web MVC 请求解析过程
过程
当我们发出请求的时候,会被
\spring-webmvc-5.3.23.jar!\org\springframework\web\servlet\DispatcherServlet.java#service()
所拦截(在父类FrameworkServlet
实现了)
获取请求方式,只要不是PATCH
的请求就会去调用FrameworkServlet
的父类HttpServletBean
的父类HttpServlet
的service
方法
这里实际上是根据不同的请求方法,调用对应的方法,例如GET
请求会调用doGet
方法
最后调用processRequest
方法
在这里调用了doService
方法之后
还继续把请求包和返回包传入doDispatch
方法中
在doDispatch
方法中,首先会对multipart
请求进行处理,然后获取对应的mappedHandler
,如何获取呢,其实就是使用了getHandler
方法
跟进getHandler
方法,发现是循环调用handlerMappings
数组的getHandler
方法对我们的请求报文进行处理
跟进第一个值的getHandler
方法,也就是\spring-webmvc-5.3.23-sources.jar!\org\springframework\web\servlet\handler\AbstractHandlerMapping.java#getHandler()
,他先进行了一次getHandlerInternal
方法对请求的报文进行处理
跟进getHandlerInternal
方法,发现是从request
对象中获取请求的path
跟进initLookupPath
,初始化请求映射的路径,并且通过
1 |
|
最后获取到我们请求的路径/hello;
接下来就去用到UrlPathHelper
工具类的removeSemicolonContent
方法,对于当前处理的URI,如果设置了setRemoveSemicolonContent
属性为true
,则继续把路径丢给removeSemicolonContentInternal
方法,否则删除Jsessionid
然后这个方法其实就是去寻找;
并且删除掉;
这里可以仔细去看看他的删除逻辑,也可以本地写个demo测一下即可,我本地测了一下之后解释如下
- 先找到
;
的位置 比如/jsp/files;.js
他就会找到;
之前一共有几位 这里就是10
位 - 然后接下来就是做判断,判断
;
后面是否存在/
,如果存在/
,则继续索引,比如/hello/..;1111/hello
这里就是会索引到第14
位,然后把索引到的两个数字丢进delete
去截取(简单理解为就是删掉;
之后到/
的所有字符串) - 如果不存在
/
就直接返回;
之前的东西就行
所以返回的结果就会删掉了;
以及其后面的内容了
接着返回了我们请求的路径后就把我们的路径作为参数给到lookupHandlerMethod
方法调用,首先直接根据路径获取对应的Mapping,获取不到的话调用addMatchingMappings
遍历所有的ReuqestMappingInfo
对象并进行匹配
跟进addMatchingMappings
,遍历识别到的ReuqestMappingInfo
对象并进行匹配
再去调用 getMatchingMapping
方法
跟进getMatchingCondition
方法,getMatchingCondition
不同版本的实现也是不一样的,高版本会使用PathPattern
来进行URL匹配(不同版本会有差异,在 2.6之前,默认使用的是AntPathMatcher进行的字符串模式匹配)
接着走到核心点再次调用getMatchingCondition
方法
进入到\spring-webmvc-5.3.23-sources.jar!\org\springframework\web\servlet\mvc\condition\PathPatternsRequestCondition.java#getMatchingCondition()
如果模式与路径相等,直接返回模式,否则进行后缀模式匹配,这里涉及到两个属性SuffixPatternMatch
&TrailingSlashMatch
,根据这两个属性的boolean值会调用pathMatcher#match
方法进行进一步的匹配
这里就小跟一下罢了,剩下的就要再深层点了
审计案例
海康威视综合安防系统
POC
1 |
|
CAS的配置如下,其实就是以下的接口或者说是后缀是不鉴权的
找到上传的控制器
/bin/tomcat/apache-tomcat/webapps/center/WEB-INF/classes/com/hikvision/center/module/faq/controller/KnowledgeController.java#uploadFile()
发现是把上传的文件名取出来直接丢到了son = this.knowledgeService.uploadFile(file);
中
跟进knowledgeService.uploadFile
发现也就是单纯拼接文件名并没有过滤,但是因为会鉴权,然后因为CAS的配置文件的问题,所以我们可以巧妙的利用SpringbootWebMVC的removeSemicolonContentInternal
通过;
来与不鉴权的后缀进行拼接从而映射到该路由下
/center/api/files
-> 鉴权
/center/api/files;.js
-> 不鉴权 -> 可以删除;.js