文章目录
- 背景
- 解决
- pdfbox依赖
- 控制器代码
- PdfUtils工具类
- 验证
- 最后
- 源码参考
背景
- 上传xss-pdf造成存储型xss
- 因为在浏览器直接预览的PDF,而不是预览,所以安全部门认为会有XSS漏洞
解决
- 安全部门修复建议
1、根据白名单的标签和属性对数据进行过滤,以此来对可执行的脚本进行清除(如script标签,img标签的onerror属性等)。
2、对输入的数据进行HTML转义,使其不会识别为可执行脚本。
pdfbox依赖
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.31</version></dependency>
控制器代码
@PostMapping("upload")public Object upload(MultipartFile file, HttpServletRequest request) throws IOException {// 文件后缀String fileName = file.getOriginalFilename();String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();// 判断是否是pdf文件类型if (StrUtil.equals(suffix, "pdf")) {// 判断文件xss攻击boolean haveJavaScript = PdfUtils.containsJavaScript(PdfUtils.multipartFileToFile(file));if (haveJavaScript) {return ("对不起,您上传的文件[" + fileName + "]包含xss脚本代码!");}}return "上传成功";}
PdfUtils工具类
/*** 获取不带扩展名的文件名*/public static String getFileNameNoSuffix(String filename) {if ((filename != null) && (filename.length() > 0)) {int dot = filename.lastIndexOf('.');if ((dot > -1) && (dot < (filename.length()))) {return filename.substring(0, dot);}}return filename;}/*** 获取文件扩展名*/public static String getSuffixNameName(String filename) {if ((filename != null) && (filename.length() > 0)) {int dot = filename.lastIndexOf('.');if ((dot > -1) && (dot < (filename.length() - 1))) {return filename.substring(dot + 1);}}return filename;}/*** File转MultipartFile** @param mulFile 文件对象* @return Multipart文件对象*/public static File multipartFileToFile(MultipartFile mulFile) throws IOException {InputStream ins = mulFile.getInputStream();String fileName = mulFile.getOriginalFilename();String prefix = getFileNameNoSuffix(fileName) + UUID.randomUUID().toString();String suffix = "." + getSuffixNameName(fileName);File toFile = File.createTempFile(prefix, suffix);OutputStream os = new FileOutputStream(toFile);int bytesRead = 0;byte[] buffer = new byte[8192];while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {os.write(buffer, 0, bytesRead);}os.close();ins.close();return toFile;}/*** 校验pdf文件是否包含js脚本**/public static boolean containsJavaScript(File file) throws IOException {RandomAccessFile is = new RandomAccessFile(file, "r");try {PDFParser parser = new PDFParser(is);parser.parse();PDDocument doc = parser.getPDDocument();String CosName = doc.getDocument().getTrailer().toString();if (CosName.contains("COSName{JavaScript}") || CosName.contains("COSName{JS}")) {return true;}} catch (Exception e) {log.error("PDF效验异常:" + e.getMessage());return true;} finally {is.close();}return false;}
验证
- 上传一个带有XSS的PDF, 可以在资源绑定下载实例pdf或者连接下载
- https://download.csdn.net/download/u010800804/89095359
- 其他没有XSS的PDF正常上传
最后
源码参考
- https://gitcode.com/rundreamsFly/java-upload-file-pdf-xss/tree/main