避免公式注入,保留单元格值(HSSF/*.xls 中的引号前缀)

Nik*_*los 3 java apache-poi

我正在开发的应用程序使用 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后打开生成的文件:

重现问题的截图

并按照以下步骤操作:

  1. 单击 (A) 以选择包含恶意内容的单元格
  2. 单击 (B) 使光标位于公式编辑器中
  3. 按 ENTER
  4. 系统会询问您是否允许 Excel 运行外部应用程序;如果您回答是,则 Calc 已启动(或任何恶意代码)

有人可能会说,用户负责让 Excel 运行任意的东西,用户被警告。但是,Excel 是从可信来源下载的,有人可能会落入陷阱。

使用 Excel,您可以在公式编辑器中的文本前放置单引号以将其转义。以编程方式在单元格内容中放置单引号(例如下面的代码)使单引号可见!

String cellValue = cell.getStringCellValue();
if( cellValue != null && "=-+@".indexOf(cellValue.charAt(0)) >= 0 ) {
    cell.setCellValue("'" + cellValue);
}
Run Code Online (Sandbox Code Playgroud)

问题:有没有办法在公式编辑器中保持值转义,但在单元格中显示正确的值,没有前导单引号?

使用 Excel 手动编辑时的预期结果

Gag*_*arr 5

感谢这里Axel Richter这里的Nikos Paraskevopoulos的辛勤工作......

Apache的POI 3.16测试版1日起(或为那些谁住危险,20161105之后的任何每晚构建),上有方便的方法CellStylegetQuotePrefixedsetQuotePrefixed(布尔)

您的代码可能会变成:

// 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);
}
Run Code Online (Sandbox Code Playgroud)