常见文件读写
常见文件读写方式
- 通过FileInputStream读取文件并使用FileOutputStream写入另一个文件的测试方法
- 通过BufferedInputStream读取文件并使用BufferedOutputStream写入另一个文件的测试方法
- 通过BufferedReader读取文件并使用BufferedWriter写入另一个文件的测试方法
- 通过FileWriter和BufferedWriter将数据附加到文件末尾的测试方法
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Test {
// 通过FileInputStream读取文件并使用FileOutputStream写入另一个文件的测试方法
@org.junit.jupiter.api.Test
public void test1() throws IOException {
// 字节流 对文件读取
// 输入字节流对象
FileInputStream in = new FileInputStream("D:\\javaweb123\\javaweb\\fileweb\\src\\main\\webapp\\test.txt");
// 输出字节流对象
FileOutputStream out = new FileOutputStream("D:\\m.txt");
// 定义字节数组
byte[] b = new byte[1024]; // 定义固定长度
int len = -1;
while ((len = in.read(b, 0, b.length)) != -1) {
String s = new String(b, 0, len, "UTF-8");
System.out.println(s);
out.write(b, 0, len);
}
out.close();
in.close();
}
// 通过BufferedInputStream读取文件并使用BufferedOutputStream写入另一个文件的测试方法
@org.junit.jupiter.api.Test
void Test02() throws IOException {
BufferedInputStream in = new BufferedInputStream(
new FileInputStream("D:\\javaweb123\\javaweb\\fileweb\\src\\main\\webapp\\test.txt"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\m.txt"));
byte[] b = new byte[1024];
int len = -1;
while ((len = in.read(b, 0, b.length)) != -1) {
String str = new String(b, 0, len, "utf-8");
System.out.println(str);
out.write(b, 0, len);
}
// 刷新缓存
out.flush();
// 关闭流
in.close();
out.close();
}
// 通过BufferedReader读取文件并使用BufferedWriter写入另一个文件的测试方法
@org.junit.jupiter.api.Test
void Test03() throws IOException {
// 带缓存的字节流读取
BufferedReader in = new BufferedReader(
new InputStreamReader(new FileInputStream("D:\\javaweb123\\javaweb\\fileweb\\src\\main\\webapp\\test.txt"), "UTF-8"));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\m.txt"), "UTF-8"));
String str;
while ((str = in.readLine()) != null) {
System.out.println(str);
out.write(str + "\n");
}
out.flush();
in.close();
out.close();
}
// 通过FileWriter和BufferedWriter将数据附加到文件末尾的测试方法
@org.junit.jupiter.api.Test
void Test04() throws IOException {
String data = "插入到文件尾的内容";
File file = new File("d:\\11.txt");
if (!file.exists()) {
file.createNewFile();
}
// 参数true为append模式
FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(data);
bw.close();
fw.close();
}
}
任意文件读取
任意文件读取是属于文件操作漏洞的一种,一般任意文件读取漏洞可以读取配置信息甚至系统重要文件。其中的目录遍历是由于web服务器或者web应用程序对用户输入的文件名称的安全性验证不足而导致的一种安全漏洞,使得攻击者通过利用一些特殊字符就可以绕过服务器的安全限制,访问任意的文件(可以是web根目录以外的文件),甚至执行系统命令。更严重的,导致SSRF漏洞,进而漫游至内网。
package com.example.file_operations;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@WebServlet("/fileread")
public class FileReadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求和响应的字符编码为UTF-8
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 获取请求参数中的文件名
String filename = req.getParameter("filename");
// 构建文件相对路径
// String relativePath = "/uploads/" + filename;
// 获取真实路径的目录
String realDir = getServletContext().getRealPath("/uploads");
// 构建文件路径
String filePath = realDir + File.separator + filename;
// 创建File对象
File file = new File(filePath);
// 检查文件是否存在
if (!file.exists()) {
resp.getWriter().write("文件不存在");
return;
}
// 使用带缓冲的输入流读取文件内容
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) {
byte[] b = new byte[1024];
int len;
// 逐块读取文件内容并写入响应
while ((len = in.read(b, 0, b.length)) != -1) {
String str = new String(b, 0, len, "utf-8");
resp.getWriter().write(str);
}
}
}
}
漏洞分析
// 获取请求参数中的文件名
String filename = req.getParameter("filename");
// 获取真实路径的目录
String realDir = getServletContext().getRealPath("/uploads");
// 构建文件路径
String filePath = realDir + File.separator + filename;
//没有对 filename 过滤,导致任意文件读取
任意文件下载
一些网站由于业务需求,往往需要提供文件查看或文件下载功能,但若对用户查看或下载的文件不做限制,则恶意用户就能够查看或下载任意敏感文件。
package com.example;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
@WebServlet("/filedown")
public class FileDownloadServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置编码集(解码)
request.setCharacterEncoding("UTF-8");
// 设置响应的编码集
response.setContentType("text/html;charset=utf-8");
if(request.getParameter("filename")==null ||request.getParameter("filename").equals("") ){
response.getWriter().write("文件不能为空");
return;
}
String fileName=request.getParameter("filename");
//通知浏览器以下载的方式打开
response.addHeader("Content-Type", "application/octet-stream");
response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName));
//通过文件流读取文件
String path= request.getSession().getServletContext().getRealPath("/uploads/");
//针对要下载的文件创建了输入流
FileInputStream in=new FileInputStream(path+fileName);
//获取response的输出流
ServletOutputStream out= response.getOutputStream();
byte[]buffer=new byte[1024];
int len=-1;
while((len=in.read(buffer))!=-1){
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}
漏洞分析
String path= request.getSession().getServletContext().getRealPath("/uploads/");
//没有限制文件名
任意文件写入
任意文件写入漏洞(Arbitrary File Write)是一种常见的安全漏洞,攻击者可以利用此漏洞将任意数据写入到服务器上的任意位置,从而可能导致服务器上的敏感信息泄漏或系统被控制。
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@WebServlet("/filewrite")
public class FilewriteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String realPath = req.getSession().getServletContext().getRealPath("/");
String filename = req.getParameter("filename");
String content = req.getParameter("content");
File file = new File(filename);
FileOutputStream out = new FileOutputStream(realPath+file);
out.write(content.getBytes());
out.close();
resp.getWriter().write(realPath+file);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
漏洞分析
FileOutputStream out = new FileOutputStream(realPath+file);
//没有过滤,直接写入服务器
任意文件删除
程序提供删除功能,对传入的参数过滤不严 导致可以删除任意文件。可以删除系统 网站中的文件。严重破坏网站正常运行。
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
@WebServlet("/filedelete")
public class FileDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String filename = req.getParameter("filename");
String realPath = req.getSession().getServletContext().getRealPath("/");
File file = new File(realPath+filename);
if(file.exists()){
file.delete();
resp.getWriter().write("文件已经删除"+ realPath+filename);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
漏洞分析
String filename = req.getParameter("filename");
String realPath = req.getSession().getServletContext().getRealPath("/");
//文件名可控,直接拼接至realPath中处理
任意文件拷贝
对参数没有进行有效过滤。导致文件在在使用过程中可以被拷贝。例如上传文件后缀名 限制为图片类型 jpg
通过拷贝 脚本类型的jsp文件。对路径没有限制 拷贝系统敏感文件到网站目录下载。
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@WebServlet("/filecopy")
public class FileCopyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String realPath = req.getSession().getServletContext().getRealPath("/");
Path path = Files.copy(Paths.get(realPath+req.getParameter("s")), Paths.get(realPath+req.getParameter("d")));
resp.getWriter().write(path.toString());
}
}
漏洞分析
Path path = Files.copy(Paths.get(realPath+req.getParameter("s")), Paths.get(realPath+req.getParameter("d")));
//未过滤,直接拼接,参数可控制
任意文件移动
跟文件拷贝漏洞类似,对传入的参数没有进行有效过滤 在移动重名的时候产生漏洞。
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
@WebServlet("/filerename")
public class FileRenameServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String s = req.getParameter("s");
String d = req.getParameter("d");
String realPath = req.getSession().getServletContext().getRealPath("/");
File files = new File(realPath + s);
File filed = new File(realPath + d);
files.renameTo(filed);
resp.getWriter().write(filed.getAbsolutePath()+"\t"+filed.exists());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
漏洞分析
File files = new File(realPath + s);
File filed = new File(realPath + d);
files.renameTo(filed);
//未过滤,直接拼接,参数可控制
目录遍历漏洞
任意目录遍历漏洞顾名思义攻击者可以通过漏洞遍历出服务器操作系统中的任意目录文件名,从而导致服务器敏感信息泄漏,某些场景下(如遍历出网站日志、备份文件、管理后台等)甚至可能会导致服务器被非法入侵。
package com.example.file_operations;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/filelist")
public class FileListServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置编码集(解码)
request.setCharacterEncoding("UTF-8");
// 设置响应的编码集
response.setContentType("text/html;charset=utf-8");
if(request.getParameter("dir")==null ||request.getParameter("dir").equals("") ){
response.getWriter().write("目录不能为空");
return;
}
//根据逻辑路径获取物理路径
//获取目录
String dir = request.getParameter("dir");
//获取相对路径
String path = request.getServletContext().getRealPath("/" + dir);
File file=new File(path);
File[] files= file.listFiles();
// List<String> fileNames=new ArrayList<String>();
for(File f:files){
String fileName=f.getName();
response.getWriter().write(fileName+"<br>");
}
}
}
漏洞分析
String path= request.getSession().getServletContext().getRealPath("/uploads/"+request.getParameter("dir"));
//直接拼接,未有效过滤
标签:审计,Java,String,FileOperations,req,new,import,servlet,javax
From: https://www.cnblogs.com/Gp3r/p/17994712