文件上传与下载是项目中经常需要提供的功能,不管是哪个web应用几乎都可以找到.那本屌今天就来说一说我们在开发中的疏忽可能导致的问题. 先建立一个web工程,目录结构如下
文件上传漏洞
我们来看看下面这段文件上传代码,使用的是common-fileupload.jar 和common-io.jar UploadServlet.java 访问路径/UploadServlet
/**
* 文件上传
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String root = request.getServletContext().getRealPath("/upload");
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> list = upload.parseRequest(request);
for(FileItem it:list){
//如果是file文件类型
if(!it.isFormField()){
it.write(new File(root+"/"+it.getName()));
response.getWriter().write("success");
}
}
} catch (Exception e) {
try {
response.getWriter().write("exception");
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
前端index.jsp有一个上传文件的表单
我们将项目发布到tomcat并且访问http://localhost:8080/load/ [+]查看原图 选择要上传的文件提交表单.文件上传也成功,在upload目录下也有我们所上传的文件. (如果是你一个刚毕业刚入行的新人,你可能看不出任何问题),可能很多老鸟大神都知道这个上传功能存在什么问题,要骂我sb! 对没错,这个功能还有一个最大的问题就是没有对上传的文件格式做限制,如果我这里实现写好了一个脚本a.jsp代码如下
<%@page import="java.io.File"%>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
String root = request.getServletContext().getRealPath("");
out.write("系统部署绝对路径:"+root);
File file = new File(root+"/index.jsp");
file.delete();
%>
上传完毕,我们在访问localhost:8080/load/upload/a.jsp,然后你在返回你就会发现一件恐怖的事情,这里不限于做删除操作,还可以自定义主页,看你自己怎么写了! 所以说我们在做上传的时候必须要对上传的文件格式做处理,在上传的时候加入一句判断语句(当然只判断后缀,还可能存在一些问题,最好在加上判断文件前4个字节一起判断[不同文件类型前4字节不同]),这样就能很好的避免上述问题!
//根据业务不同自定义
if(it.getName().contains("jsp")){
//return
}
文件下载漏洞(目录遍历攻击)
下面再来看看文件下载中的安全问题 DownLoad.java 访问路径 /DownLoad
/**
* 文件下载
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取项目部署绝对路径下的upload文件夹路径,我们下载upload目录下面的文件
String root = request.getServletContext().getRealPath("/upload");
//获取文件名
String filename = request.getParameter("filename");
File file = new File(root+"/"+filename);
//根据文件路径创建输入流
FileInputStream fis = new FileInputStream(file);
//设置响应头,弹出下载框
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
response.addHeader("Content-Length", "" + file.length());
byte[] b = new byte[fis.available()];
fis.read(b);
response.getOutputStream().write(b);
}
index.jsp 加入一个新表单
这里我们输入要下载的文件名,submit后会访问后台的DownLoad,DownLoad里面我们获取文件名称,然后获取输入输出流对文件进行下载.操作结果成功下载文件
上述的下载代码90%的人都是那样写的,这里面的问题就不是那么容易看出来了,尽管你可能已经工作的有些时候了。
下面在文本框中输入[../WEB-INF/web.xml],submit后,你就会下载到一个很惊恐的文件!
下载之后打开
结尾
这里不限于../ 还能更多上下级目录,这就是"目录遍历攻击"!
如果在C盘根目录下有个a.txt文件 c:/a.txt
File f = new File("c:/a/b/c/../../../a.txt"); 也能够访问到
通过这类方式还能访问到你system32目录大家可以在百度去看看相关的知识。
至于解决方案大家多半也知道了需要对文件名称进行特殊字母的判断。window上不允许文件有特殊字符,我们在程序里面也需要处理,不能包含 / 之类的,不要相信前端传来的数据. 骚年感觉去看看自己的代码是不是这样写的!!