如何用开源Java工具(如PDFBox)清理PDF?Spring应用文件上传安全处理
增强Spring文件上传模块安全性的方案
一、前置基础校验
先做最核心的拦截,避免恶意文件进入后续处理流程:
- 扩展名+文件头双重校验:
不要仅依赖文件名后缀,读取文件前几个字节判断真实类型(即魔术字节):- PDF:
%PDF- - DOCX:
PK\x03\x04 - XLS:
D0CF11E0 - JPG:
FFD8FF
实现时可写工具类,读取输入流前N字节做匹配,不匹配直接拒绝上传。
- PDF:
- 严格限制文件大小:
在Spring配置中设置spring.servlet.multipart.max-file-size和spring.servlet.multipart.max-request-size,或在代码中通过MultipartFile.getSize()直接判断,超出阈值直接拦截。
二、针对不同文件类型的内容清理
1. PDF文件清理(基于PDFBox)
PDF的危险点主要是JavaScript、自动执行动作、嵌入式文件、恶意注解,用PDFBox可直接移除这些内容:
依赖引入(Maven)
<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.32</version> </dependency>
清理核心代码
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.interactive.action.PDAction; import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class PdfCleaner { public static void cleanPdf(InputStream inputStream, OutputStream outputStream) throws IOException { try (PDDocument document = PDDocument.load(inputStream)) { // 移除文档级自动执行动作(如打开时运行脚本) document.getDocumentCatalog().setOpenAction(null); // 遍历所有页面,清理页面动作与注解中的恶意内容 for (PDPage page : document.getPages()) { page.setActions(null); // 清空页面关联的所有动作 if (page.getAnnotations() != null) { for (PDAnnotation annotation : page.getAnnotations()) { // 移除链接注解中的JavaScript动作 if (annotation instanceof PDAnnotationLink) { PDAnnotationLink link = (PDAnnotationLink) annotation; PDAction action = link.getAction(); if (action instanceof PDActionJavaScript) { link.setAction(null); } } annotation.setActions(null); // 清空注解自带的动作 } } } // 移除嵌入式文件(防止隐藏恶意程序) if (document.getDocumentCatalog().getNames() != null) { document.getDocumentCatalog().getNames().setEmbeddedFiles(null); } // 保存清理后的文档 document.save(outputStream); } } }
2. Office文档(XLS、DOCX)清理
Office文档的风险点是宏、嵌入式对象、恶意公式,用Apache POI处理:
- DOCX:使用
XWPFDocument遍历段落和表格,提取纯文本后重新生成无宏的干净文档,或直接删除宏相关的XML部件; - XLS:使用
HSSFWorkbook/XSSFWorkbook移除宏模块、嵌入式对象,禁用自动计算公式(通过设置setForceFormulaRecalculation(false))。
3. 图片文件处理
图片可能携带恶意元数据(如EXIF中的脚本)或隐写内容,通过重新编码清除:
import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.InputStream; import java.io.OutputStream; public class ImageCleaner { public static void cleanImage(InputStream inputStream, OutputStream outputStream, String format) throws IOException { BufferedImage image = ImageIO.read(inputStream); // 重新编码后会丢失所有元数据,仅保留图像本身 ImageIO.write(image, format, outputStream); } }
三、上传全流程安全管控
- 文件存储规则:上传后用UUID生成随机文件名,避免路径遍历攻击;存储目录不要放在Web根目录下,禁止直接通过URL访问;
- 二次扫描:除上传前的杀毒检测,可定时对已存储文件进行病毒扫描,弥补单次扫描的遗漏;
- 权限控制:仅允许授权用户上传,下载文件时校验用户权限,防止未授权访问;
- 目录权限设置:存储文件的目录设置为不可执行,即使文件被篡改也无法在服务器上运行。
内容的提问来源于stack exchange,提问作者Faisul
相关产品推荐
相关产品推荐

