Spring?Mvc中CommonsMultipartFile的特性實(shí)例詳解
前言:
簡單的記錄下Spring <= 4.1.8的CommonsMultipartFile的特性,遇到一個springmvc的一套系統(tǒng)通過該方法進(jìn)行繞過上傳解決,不過只限于windows的情況下,這篇筆記先介紹下關(guān)于CommonsMultipartFile,然后給出實(shí)例利用的情況
參考文章:https://forum.butian.net/share/815
MultipartFile是什么
在springmvc中進(jìn)行文件上傳的時候,springmvc提供了兩個封裝好的上傳組件來進(jìn)行使用,如下圖所示,分別是CommonsMultipartFile和StandardMultipartFile

StandardMultipartFile
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.8.RELEASE</version>
</dependency>
如果要使用StandardServletMultipartResolver進(jìn)行文件上傳,需要進(jìn)行如下兩個步驟
先在springmvc-servlet.xml中配置如下multipartResolver為StandardServletMultipartResolver
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

然后在web.xml中還需要進(jìn)行如下配置multipart-config,配置在DispatcherServlet的servlet標(biāo)簽中
<multipart-config>
<!--上傳的文件的最大限制,單位byte-->
<max-file-size>4194304</max-file-size>
<!--multipart/form-data請求的最大限制,單位byte-->
<max-request-size>10485760</max-request-size>
<!--將存儲上載文件的目錄位置-->
<!--<location></location>-->
</multipart-config>

對于StandardMultipartFile類中有一個問題就是在獲取文件名的時候?qū)崿F(xiàn)的getOriginalFilename方法是直接獲取文件名,沒有進(jìn)行過濾一些特殊字符的情況,這樣的情況就會產(chǎn)生安全問題比如路徑跳躍
UploadController.java
@Controller
public class UploadController {
@RequestMapping(value = "/fileupload")
@ResponseBody
public String test(HttpServletRequest request) throws Exception {
MultipartHttpServletRequest req = (MultipartHttpServletRequest)request;
MultipartFile file = req.getFile("uploadFile");
String realFileName = file.getOriginalFilename();
String ctxPath = req.getSession().getServletContext().getRealPath("/tmp/");
File dirPath = new File(ctxPath);
if (!dirPath.exists()) {
dirPath.mkdir();
}
String serverPath = ctxPath + File.separator + realFileName;
try {
File uploadFile = new File(serverPath);
FileCopyUtils.copy(file.getBytes(), uploadFile);
return serverPath;
} catch (Exception var9) {
var9.printStackTrace();
return "upload fail";
}
}
}
上面代碼的情況下,我們直接上傳文件的話會存在目錄跳躍的問題,結(jié)果如下所示,可以看到readme.jsp可以直接跳出tmp目錄

這里主要問題出在getOriginalFilename方法,這里可以觀察下StandardMultipartFile的getOriginalFilename,下面的圖中可以看到?jīng)]有對../這些符號做相關(guān)的限制

CommonsMultipartFile
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.8.RELEASE</version>
</dependency>
這里可以將代碼改為CommonsMultipartFile來進(jìn)行測試
將springmvc-servlet.xml中配置如下multipartResolver為CommonsMultipartResolver
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

重新進(jìn)行發(fā)包可以發(fā)現(xiàn)就不會出現(xiàn)目錄跳躍的問題了

這里同樣可以看下org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename,可以看到首先就會匹配/符號,然后取/之后的內(nèi)容

這里主要利用了org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename,而這里有個邏輯問題就是如果在windows下的話\\同樣可以作為分隔符來進(jìn)行識別,所以如果對于/..\..\readme.jsp這種payload的話,那么在windows的情況下同樣可以進(jìn)行利用

這邊拿windows的環(huán)境來進(jìn)行測試,結(jié)果如下所示

調(diào)試過程可以看到org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename最終取到的就是/之后的內(nèi)容

漏洞修復(fù)
這邊將pom.xml中的springmvc修改為4.1.9.RELEASE
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.9.RELEASE</version>
</dependency>
重新測試的情況下,就無法進(jìn)行繞過了

實(shí)戰(zhàn)遇到的代碼
這邊拿前面篇頭說的實(shí)際審計(jì)的情況,這個環(huán)境下是在/tmp/目錄下禁止訪問,所以如果要利用的話那么就需要上傳的文件不在該目錄下,那么這邊的話就可以用getOriginalFilename跨越目錄,用/..\..\readme.jsp來利用即可
public static String upLoadFile(HttpServletRequest request) {
MultipartHttpServletRequest req = (MultipartHttpServletRequest)request;
MultipartFile file = req.getFile("uploadFile");
String realFileName = file.getOriginalFilename();
String ctxPath = request.getContextPath();
ctxPath = req.getSession().getServletContext().getRealPath("/tmp/");
File dirPath = new File(ctxPath);
if (!dirPath.exists()) {
dirPath.mkdir();
}
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String serverPath = ctxPath + File.separator + format.format(new Date()) + realFileName;
try {
File uploadFile = new File(serverPath);
FileCopyUtils.copy(file.getBytes(), uploadFile);
return serverPath;
} catch (Exception var9) {
var9.printStackTrace();
return null;
}
}
總結(jié)
到此這篇關(guān)于Spring Mvc中CommonsMultipartFile特性的文章就介紹到這了,更多相關(guān)Spring Mvc CommonsMultipartFile特性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)延遲隊(duì)列的全流程詳解
Redisson是Redis服務(wù)器上的分布式可伸縮Java數(shù)據(jù)結(jié)構(gòu),這篇文中主要為大家介紹了Redisson實(shí)現(xiàn)的優(yōu)雅的延遲隊(duì)列的方法,需要的可以參考一下2023-03-03
在IntelliJ IDEA 搭建springmvc項(xiàng)目配置debug的教程詳解
這篇文章主要介紹了在IntelliJ IDEA 搭建springmvc項(xiàng)目配置debug的教程詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
我勸你謹(jǐn)慎使用Spring中的@Scheduled注解
這篇文章主要介紹了Spring中的@Scheduled注解使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Java Netty實(shí)現(xiàn)心跳機(jī)制過程解析
這篇文章主要介紹了Java Netty實(shí)現(xiàn)心跳機(jī)制過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
生產(chǎn)者消費(fèi)者模型ThreadLocal原理及實(shí)例詳解
這篇文章主要介紹了生產(chǎn)者消費(fèi)者模型ThreadLocal原理及實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09

