struts2安全插件struts2-secure-jakarta-multipart-parser-plugin引起的文件上传问题

Posted zjhgx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了struts2安全插件struts2-secure-jakarta-multipart-parser-plugin引起的文件上传问题相关的知识,希望对你有一定的参考价值。

新项目的框架是ssh,用到了struts2的文件上传功能,但发现项目在eclipse启动后,只有第一次上传文件是ok的,以后上传就报

2018-01-09 21:32:16 [http-nio-8080-exec-7] ERROR: com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl#save : Source /home/vobile/workspace_trph/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/work/Catalina/localhost/lexiao-admin/upload_2df39ff2_d4c7_49ef_a521_925b0e85c43a_00000001.tmp does not exist
java.io.FileNotFoundException: Source /home/vobile/workspace_trph/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/work/Catalina/localhost/lexiao-admin/upload_2df39ff2_d4c7_49ef_a521_925b0e85c43a_00000001.tmp does not exist
    at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:1004)
    at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:968)
    at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl.save(AttachmentServiceImpl.java:367)
    at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl.save(AttachmentServiceImpl.java:217)
    at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl$$FastClassByCGLIB$$99f22be.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)

因为struts默会把文件放在/tmp1下面,生成了一个xxxx.tmp的临时文件,而报这个错是这个临时文件找不到,跟踪了下struts2的FileUploadInterceptor,

        Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
        while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
            // get the value of this input tag
            String inputName = (String) fileParameterNames.nextElement();

            // get the content type
            String[] contentType = multiWrapper.getContentTypes(inputName);

            if (isNonEmpty(contentType)) {
                // get the name of the file from the input tag
                String[] fileName = multiWrapper.getFileNames(inputName);

                if (isNonEmpty(fileName)) {
                    // get a File object for the uploaded File
                    File[] files = multiWrapper.getFiles(inputName);
                    if (files != null && files.length > 0) {
                        List<File> acceptedFiles = new ArrayList<File>(files.length);
                        List<String> acceptedContentTypes = new ArrayList<String>(files.length);
                        List<String> acceptedFileNames = new ArrayList<String>(files.length);
                        String contentTypeName = inputName + "ContentType";
                        String fileNameName = inputName + "FileName";

                        for (int index = 0; index < files.length; index++) {
                            if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) {
                                acceptedFiles.add(files[index]);
                                acceptedContentTypes.add(contentType[index]);
                                acceptedFileNames.add(fileName[index]);
                            }
                        }

                        if (!acceptedFiles.isEmpty()) {
                            Map<String, Object> params = ac.getParameters();

                            params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()]));
                            params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()]));
                            params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()]));
                        }
                    }
                } else {
                    if (LOG.isWarnEnabled()) {
                        LOG.warn(getTextMessage(action, "struts.messages.invalid.file", new String[]{inputName}));
                    }
                }
            } else {
                if (LOG.isWarnEnabled()) {
                    LOG.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[]{inputName}));
                }
            }

发现acceptedFiles有多个文件,准确的说是之前上传了多少个就有多少个,而我一次其实只上传了一个文件,而临时目录里也只有我这次上传的文件,对应到java代码里只会接受一个文件,默认取了第一个_00000001.tmp,而实际存在的是_00000004.tmp,那就报错了。

为什么呢?当时怀疑是前端的问题,但没发现原因。后来我单独用postman向后端上传文件,发现问题依旧,说明是后端的问题。最后是注释掉了以前加的一个struts2的安全插件

struts.xml

 

<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
           class="org.apache.struts.extras.SecureJakartaMultipartParser"
           name="secure-jakarta"
           scope="prototype"/> 
   
     <constant name="struts.multipart.parser" value="secure-jakarta"/>     

 

把struts.xml里的这段注释掉就好了。

那又是什么最终的原因呢?还没开始分析那个插件,待续。

 

以上是关于struts2安全插件struts2-secure-jakarta-multipart-parser-plugin引起的文件上传问题的主要内容,如果未能解决你的问题,请参考以下文章

关于Apache Struts2 REST插件存在S2-052远程代码执行漏洞的安全公告

Struts2 REST插件远程执行命令漏洞全面分析,WAF支持检测防御

安全通告|Struts2(S2-052)远程命令执行漏洞

CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告

每日安全资讯漏洞预警 | 高危Struts REST插件远程代码执行漏洞(S2-052)

Struts2 Convention插件远程代码执行