1.这种攻击不会出现在BS的应用中,因为要从web页面模拟攻击比较累。而CS程序则天生可能会隐藏这种问题。
2.经过认真的跟进,最终发现问题出在sizeThreshold 这个参数上。
让人费解的来由是:
org.apache.commons.fileupload.FileUploadBase这个基类351行,解析request调用了
OutputStream os = item.getOutputStream();
跟进去看方法实现:
public OutputStream getOutputStream()
throws IOException {
if (dfos == null) {
File outputFile = getTempFile();
dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
}
return dfos;
}
再进去看getTempFile,发现这里创建了文件
protected File getTempFile() {
File tempDir = repository;
if (tempDir == null) {
tempDir = new File(System.getProperty("java.io.tmpdir"));
}
String fileName = "upload_" + UID + "_" + getUniqueId() + ".tmp";
File f = new File(tempDir, fileName);
FileCleaner.track(f, this);
return f;
}
也就是只要使用了fileupload组件,就会走到 getTempFile,就会创建临时文件。而文档中提到的sizeThreshold根本无用(确实整个代码跟进的过程中,sizeThreshold都没有使用到)
那么真实情况如何?
1.下面这句并不会真的在磁盘创建文件。。也是久疏基础知识,让自己的推理陷入了误区。
File f = new File(tempDir, fileName);
2.sizeThreshold这个参数(The threshold above which uploads will be stored on disk.)起作用的地方并不在common.fileupload这个项目中,而是上面getOutputStream这段代码中,将这个参数传到了common.io这个项目中的实现类。也就是项目依赖。
dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
-------------------------原帖分界线----------------------------------
最近搞人的一桩事情:
严重: Socket accept failed
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
at java.net.ServerSocket.implAccept(ServerSocket.java:453)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:61)
at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:310)
at java.lang.Thread.run(Thread.java:619)
排查很久才发现,竟然是文件上传这个地方的问题。无论有意还是恶意,都会让人恼火。
有些客户端故意使用multi-part封装全部参数, 比如"abc=111"的普通参数,经过包装后post,成了multi-part。 这样就绕过Jakarta Commons Fileupload的判断逻辑:
具体的恶劣方式如下:
1.给一个request带上20+个参数,全部变成mutiparty+ post提交。给服务器带来大量的临时文件创建、删除压力。
2.大量的请求耗时较长的接口。当linux下文件句柄消耗完, 服务停止响应。
可考虑的解决方式??
1.限制上传文件的类型, 非常有必要.
2.升级commons.fileupload 到1.2+,后面的版本有提供新的接口处理这个bug
3.改造MultiPartRequest,根据业务限制每个request带的FileItem个数。基本限制到1-2个即可。超出立即丢弃。