浅谈Java Web中Word转换器与SSRF
字数 1226 2025-10-01 14:05:44
Java Web中Word转换器与SSRF风险分析及防护
0x00 前言
在Java Web开发中,Word转PDF是常见功能需求,主要用于合同管理、公文审批、报告生成等业务场景。PDF格式具有跨平台兼容性好、难以篡改、便于存档传播等优势。然而,实现此功能时若对组件库实现细节了解不足,可能引入安全风险,特别是SSRF(Server-Side Request Forgery)漏洞。
0x01 常见Word转换器实现方式
1.1 Apache POI + iText
- 技术组合:Apache POI处理Word文档,iText生成PDF
- 实现代码:
public static void convert(String inputPath, String outputPath) throws Exception {
try (FileInputStream fis = new FileInputStream(inputPath);
FileOutputStream fos = new FileOutputStream(outputPath)) {
XWPFDocument document = new XWPFDocument(fis);
Document pdfDoc = new Document();
PdfWriter.getInstance(pdfDoc, fos);
pdfDoc.open();
for (XWPFParagraph paragraph : document.getParagraphs()) {
String text = paragraph.getText();
if (text != null && !text.isEmpty()) {
pdfDoc.add(new Paragraph(text));
}
}
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
String cellText = cell.getText();
pdfDoc.add(new Paragraph(cellText));
}
}
}
pdfDoc.close();
document.close();
}
}
- 局限性:不支持图片和复杂样式,性能一般,不适合高质量转换场景
1.2 Spire.Doc
- 特性:专业Java Word组件,无需安装Microsoft Office
- 功能:支持文档创建、读取、编辑、转换、打印等操作
- 实现代码:
// 创建Document对象并载入Word文档
Document doc = new Document(targetFile);
// 将文档保存为PDF格式
doc.saveToFile(destFile, FileFormat.PDF);
- 版本:提供商业版和免费版
1.3 LibreOffice
- 特性:功能强大的开源办公软件,支持多种文档格式
- 实现方式:通过命令行调用转换功能
- 示例代码:
public File ConvertDocxToPdf(String filename) throws IOException, InterruptedException {
synchronized (LibreOfficeLock.LOCK) {
String tempDocxFilePath = "./" + filename;
String outputPdfFileName = filename.replace(".docx", ".pdf");
String outputPdfFilePath = "./" + outputPdfFileName;
String[] command = {
"libreoffice", // Linux下为libreoffice,macOS下为soffice
"--headless",
"--convert-to",
"pdf",
"--outdir",
outputDirectory,
tempDocxFilePath
};
Process process = null;
ProcessBuilder processBuilder = new ProcessBuilder(command);
process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("Conversion failed: " + exitCode);
}
return outputDocxFile;
}
}
其他方案
- Aspose.Words for Java:功能强大的商业库
- Docx4j + XSL-FO:适合对文档样式有高度定制需求的场景
0x02 潜在SSRF风险分析
风险来源
转换组件功能强大,如LibreOffice支持HTML解析,在处理HTML内容(如img标签的URL)时可能触发远程资源请求,若URL访问无严格限制,可能导致SSRF攻击。
验证实验
- 准备恶意HTML文件:
- 使用Spire.Doc转换:
Document doc = new Document(targetFile);
doc.saveToFile(destFile, FileFormat.PDF);
- 结果:DNSlog成功接收到请求,证实SSRF风险存在
- LibreOffice测试:同样存在类似行为
0x03 常见绕过方式与修复方案
常见检测方式及绕过
-
后缀名检查
- 绕过方法:将HTML文件后缀改为.docx仍可成功解析
-
文件类型检测(hotool工具包示例)
- 检测原理:通过文件头字节判断文件类型
- 源码分析:
private static ContentType getFileType(byte[] bytes) { if (bytes.length < 14) { return ContentType.OTHERS; } byte[] bytes2 = new byte[14]; System.arraycopy(bytes, 0, bytes2, 0, 14); String fileHexString = getFileHexString(bytes2); fileHexString = fileHexString.toUpperCase(); if (fileHexString.startsWith(ContentType.DOC.getFileTitle())) { return ContentType.DOC; } else if (fileHexString.startsWith(ContentType.DOCX.getFileTitle())) { // 进一步确认docx:检查是否包含"word/"内容 byte[] bytes500 = new byte[500]; System.arraycopy(bytes, bytes.length - 500, bytes500, 0, 500); fileHexString = getFileHexString(bytes500); if (fileHexString.contains("776f72642f")) { // "word/"的十六进制 return ContentType.DOCX; } } return ContentType.OTHERS; }- 绕过方法:伪造文件头(如DOCX文件头为504B0304)
-
高级绕过技术
- 使用WPS将恶意HTML文件另存为docx格式,可成功绕过多种检测
修复方案
-
网络层防护
- 使用代理服务或防火墙限制文档转换服务的网络访问权限
- 只允许必要的外部访问,阻断所有内部网络探测行为
-
应用层防护
- 实施严格的文件类型验证,不仅检查文件头,还应验证文件内容的真实性
- 对转换服务进行沙箱隔离,限制其网络访问能力
-
代码审计重点
- 重点关注文档解析过程中可能触发外部资源请求的组件
- 积累相关漏洞模式,加强安全检测
总结
Word转换功能在Java Web应用中广泛使用,但组件强大的功能背后隐藏着SSRF风险。攻击者可通过构造恶意文档利用转换过程中的外部资源请求功能实施攻击。防护需要从网络隔离、文件验证和多层检测入手,同时开发人员需在代码审计时特别关注此类隐蔽的SSRF风险。