首页 > 编程语言 >学习笔记-java代码审计-文件操作

学习笔记-java代码审计-文件操作

时间:2022-11-13 08:44:53浏览次数:74  
标签:审计 file java String 笔记 filename File new response

java代码审计-文件操作

0x01 文件上传

这段代码来自菜鸟教程:

private static final String UPLOAD_PATH = "/tmp/upload";
private boolean uploadWithFileUpload(HttpServletRequest request) {
  if(!ServletFileUpload.isMultipartContent(request)) {
    //response.getWriter().print("Error: 表单必须包含 enctype=multipart/form-data");
    return false;
  }
	/*省略部分初始化代码*/
  try {
    List<FileItem> fileItems = servletFileUpload.parseRequest(request);
    if(fileItems != null && fileItems.size() > 0) {
      for(FileItem fileItem : fileItems) {
        String fileName = new File(fileItem.getName()).getName(); //获取文件名
        String filePath = UPLOAD_PATH + File.separator + fileName; //上传路径
        File storeFile = new File(filePath);
        fileItem.write(storeFile); //写文件
      }
      //response.getWriter().println("upload success");
    }
  } catch (Exception e) {
    //response.getWriter().print(e.getMessage());
    return false;
  }
  return true;
}

标准的任意文件上传代码。。。现在的web框架会将上传的文件放在web访问不到的位置存储,这样会一定程度上缓解上传漏洞,但如果在展示文件时处理不当,就会导致任意文件读取或下载。

servlet3之后,可以不使用commons-fileupload、commons-io这两个jar包来处理文件上传,转而使用request.getParts()获取上传文件。此外,servlet3还支持以注解的形式定义一些上传的属性。

private boolean uploadWithAnnotation(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    Part part = request.getPart("fileName");
    if(part == null) {
      return false;
    }
    String filename = UPLOAD_PATH + File.separator + part.getSubmittedFileName();
    part.write(filename);
    part.delete();
    return true;
}

可以看到这种方法代码比较简洁,需要注意的是要在类前面加@MultipartConfig这个注解,否则会报错。

防御

文件上传参考这个https://mp.weixin.qq.com/s/LzVseWzLP3CjQsmYzvELZA

  1. 判断文件content-type

  2. 文件上传后改名

    String fileExt = filename.substring(filename.lastIndexOf(".") + 1); //获取后缀名
    String savename = UPLOAD_PATH + File.separator + DigestUtils.md5Hex(System.currentTimeMillis() + filename) + "." + fileExt;
    
  3. 设置严格的后缀名白名单

    使用esapi的后缀名检测,需要在对应的resource目录建立ESAPI.propertiesvalidation.properties,文件内容可以留空,也可以下载官方内容https://github.com/ESAPI/esapi-java-legacy/blob/develop/src/test/resources/esapi

    //检测后缀名
    if(!ESAPI.validator().isValidFileName("upload", filename, ALLOW_EXT, false)) {
        response.getWriter().println("后缀名不合法");
    }
    
  4. 对文件大小进行限制

    基于ServletFileUpload

    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
    servletFileUpload.setSizeMax(1024 * 400);
    

    基于注解( version > servlet3)

    @MultipartConfig(maxFileSize = 1000 * 1024 * 1024, maxRequestSize = 1000 * 1024 * 1024)
    public class UploadServlet extends HttpServlet {}
    
  5. 条件允许的情况下,将文件放到web访问不到的位置存储

0x02 文件操作(下载/读取/删除)

这几个操作比较类似,都是对文件的操作。

java的文件读取一般有两种方法,一种是基于InputStream,另一种是基于FileReader。

读取

//InputStream
File file = new File(filename);
InputStream inputStream = new FileInputStream(file);
while(-1 != (len = inputStream.read())) {
  	outputStream.write(len);
}
//FileReader
String fileContent = "";
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = "";
while (null != (line = bufferedReader.readLine())) {
		fileContent += (line + "\n");
}

下载

读写操作都有的情况下,用流比较方便。

//stream
String filename = request.getParameter("filename");
File file = new File(filename);

response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("utf-8")));
response.addHeader("Content-Length", "" + file.length());
response.setContentType("application/octet-stream; charset=utf-8");

InputStream inputStream = new FileInputStream(file);
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
int len;
while(-1 != (len = inputStream.read())) {
  outputStream.write(len);
}

inputStream.close();
outputStream.close();

删除

String filename = request.getParameter("filename");
File file = new File(filename);
if(file != null && file.exists() && file.delete()) {
  	response.getWriter().println("delete success");
} else {
  	response.getWriter().println("delete failed");
}

防御

防御的核心在于对传入的文件名进行正确的过滤,防止跨目录。

private boolean checkFilename(String filename) {
    filename = filename.replace("\\", "/"); //消除平台差异
  	//将文件操作限定在指定目录中
  	File file = new File(filename);
    if(file == null || !file.exists() || file.getCanonicalFile().getParent().equals(new File(DOWNLOAD_PATH).getCanonicalPath())) { //检测上级目录是否为指定目录
      return false;
    }
  	//检测文件名中是否有敏感字符
    List<String> blackList = Arrays.asList("./", "../");
    for(String badChar : blackList) {
      if(filename.contains(badChar)) {
        return false;
      }
    }
  	//对文件后缀名设置白名单
    List<String> whiteExt = Arrays.asList("png", "jpg", "gif", "jpeg", "doc");
    String fileExt = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
    if(!whiteExt.contains(fileExt)) {
      return false;
    }
    return true;
}

0x03 文件写入

//FileWriter
FileWriter fileWriter = new FileWriter(filename);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(fileContent);
bufferedWriter.close();

防御

文件写入与上述三个操作略有不同,在防御时需要对写入的内容进行过滤。

private boolean checkFilecontent(String fileContent) {
    List<String> blackContents = Arrays.asList("<%@page", "<%!");
    for(String blackContent : blackContents) {
      if(fileContent.contains(blackContent)) {
        return false;
      }
    }
    return true;
}

在写入时最好将标签进行htmlencode

String fileContent = request.getParameter("content");
fileContent = ESAPI.encoder().encodeForHTML(fileContent);

点击关注,共同学习!
安全狗的自我修养

github haidragon

https://github.com/haidragon

标签:审计,file,java,String,笔记,filename,File,new,response
From: https://www.cnblogs.com/haidragon/p/16885376.html

相关文章

  • 学习笔记-java代码审计-反序列化
    Java代码审计-反序列化0x00漏洞挖掘业务代码简单来说,找readObject/readUnshared就好了protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresp......
  • 学习笔记-java代码审计-环境搭建+前置知识
    Java代码审计-环境搭建+前置知识0x00中间件tomcat因为个人比较矫情,不想在mac搭java的开发环境,就想着有没有本地写代码然后部署到虚拟机上运行。毕竟java是静态语言,在编......
  • 学习笔记-java代码审计-表达式注入
    java代码审计-表达式注入0x01漏洞挖掘spelspel表达式有三种用法:注解@value("#{表达式}")publicStringarg;这种一般是写死在代码中的,不是关注的重点。xml<b......
  • 【Javaweb】做一个房产信息管理系统三(src目录的部署工作【三层框架】各个层含义)
    接下来,我打算进行Java文件的部署工作,但实际上为了得到更多的分数,我们还是应该先做页面首先我们需要了解对于Javaweb,src下的目录应该如何部署:(三层架构单独开一篇讲) 那......
  • java.util.List如何用
    起因是这样,我在学习Javaweb,然后就突然有很多类似的语句  这是什么意思呢?让我们一起来解决看看吧!List有序集合(也成为序列),用户可以精确控制列表中每个元素的插入位置。......
  • 工业机器人基础笔记(一)
    第一章续论读者可自行学习,笔记从第二章开始。此笔记仅仅为抄录,便于复习。按照拓扑结构分类,我们把工业机器人分为三类。串联机器人并联机器人混联机器人那什么是拓扑......
  • JAVA注解(Annotation)
    注解(Annotation)什么是注解Annotation的作用:不是程序本身,可以对程序做出解释,这一点和注释(comment)没什么区别。可以被其他程序(比如编译器)读取Annotation的格式:注......
  • 【Javaweb】做一个房产信息管理系统二
    由于我还不太熟练用sql语句写数据库,所以直接用navicate了我们需要新建四个数据表:adimin(超级管理员信息)customer(顾客)property(房产信息)realestate(房产经纪人信息)我发现......
  • 【读书笔记】《Verilog HDL数字设计与综合(第二版 本科教学版)》第一章:Verilog HDL数字
    一、数字电路CAD技术的发展历史真空管晶体管,集成电路(IntegratedCircuit,IC)小规模集成电路(SmallScaleIntegrated,SSI):逻辑门数量很少中规模集成电路(MediumScaleI......
  • 02-类与对象 进行试验--Java字段初始化的规律
    1.类的构造方法(1)“构造方法”,也称为“构造函数”,当创建一个对象时,它的构造方法会被自动调用。构造方法与类名相同,没有返回值。(2)如果类没有定义构造函数,Java编译器......