我正在处理的应用程序使用Apache POI创建Excel导出。通过安全审计,我们注意到,如果用户不够谨慎,那么包含恶意值的单元格可能会产生任意进程。
要重现,请运行以下命令:
import java.io.FileOutputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
public class BadWorkbookCreator {
public static void main(String[] args) throws Exception {
try(
Workbook wb = new HSSFWorkbook();
FileOutputStream fos = new FileOutputStream("C:/workbook-bad.xls")
) {
Sheet sheet = wb.createSheet("Sheet");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("Aaaaaaaaaa");
row.createCell(1).setCellValue("-2+3 +cmd|'/C calc'!G20");
wb.write(fos);
}
}
}
然后打开生成的文件:
然后按照以下步骤操作:
可以说用户负责让Excel运行任意内容并且警告用户。但是,Excel仍然是从受信任的来源下载的,有人可能会陷入陷阱。
使用Excel,您可以在公式编辑器中的文本前放置单引号以对其进行转义。以编程方式将单引号放在单元格内容中(例如下面的代码)使单引号可见!
String cellValue = cell.getStringCellValue();
if( cellValue != null && "=-+@".indexOf(cellValue.charAt(0)) >= 0 ) {
cell.setCellValue("'" + cellValue);
}
问题:有没有办法在公式编辑器中保留值转义,但在单元格中显示正确的值,而没有前导单引号?
答案 0 :(得分:4)
感谢Axel Richter here和Nikos Paraskevopoulos here ....
的辛勤工作从Apache POI 3.16 beta 1起(或者对于生活危险的人,2016-1105之后的任何夜间构建),CellStyle getQuotePrefixed和setQuotePrefixed(boolean)上有方便的方法
您的代码可能会变为:
// Do this once for the workbook
CellStyle safeFormulaStyle = workbook.createCellStyle();
safeFormulaStyle.setQuotePrefixed(true);
// Per cell
String cellValue = cell.getStringCellValue();
if( cellValue != null && "=-+@".indexOf(cellValue.charAt(0)) >= 0 ) {
cell.setCellStyle(safeFormulaStyle);
}
答案 1 :(得分:0)
感谢来自POI团队的即时(kudos)响应(请参阅已接受的答案),此解决方案应该已过时。保留它作为参考,在无法升级到POI> = 3.16的情况下非常有用。
感谢Axel Richter的评论(我非常感谢),我设法找到了解决方案。它绝对不像XLSX文件(XSSFWorkbook
)那样简单,因为它涉及手工创建org.apache.poi.hssf.model.InternalWorkbook
; POI项目将此类标记为@Internal
,但就Java而言,它是public
。此外,设置为纠正问题的字段,即ExtendedFormatRecord.set123Prefix(true)
未记录!
以下是解决方案,了解它的价值 - 将其与问题中的代码进行比较:
import java.io.FileOutputStream;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
public class GoodWorkbookCreator {
public static void main(String[] args) throws Exception {
InternalWorkbook internalWorkbook = InternalWorkbook.createWorkbook();
try(
HSSFWorkbook wb = HSSFWorkbook.create(internalWorkbook);
FileOutputStream fos = new FileOutputStream("C:/workbook-good.xls")
) {
HSSFCellStyle style = (HSSFCellStyle) wb.createCellStyle();
ExtendedFormatRecord xfr = internalWorkbook.getExFormatAt(internalWorkbook.getNumExFormats() - 1);
xfr.set123Prefix(true); // THIS IS WHAT IT IS ALL ABOUT
Sheet sheet = wb.createSheet("Sheet");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("Aaaaaaaaaa");
row.createCell(1).setCellValue("-2+3 +cmd|'/C calc'!G20");
Cell cell = row.createCell(2);
cell.setCellValue("-2+3 +cmd|'/C calc'!G20");
cell.setCellStyle(style);
wb.write(fos);
}
}
}