diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java index 5847223da..9314665a0 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/CharPool.java @@ -91,4 +91,13 @@ public interface CharPool { * 字符常量:百分号 {@code '%'} */ char PERCENT = '%'; + /** + * 字符常量:等于 {@code '='} + */ + char EQUAL = '='; + /** + * 字符常量:减号 {@code '-'} + */ + char MINUS = '-'; + } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriteConfig.java b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriteConfig.java index 75263fa0a..9548cbc21 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriteConfig.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriteConfig.java @@ -20,6 +20,10 @@ public class CsvWriteConfig extends CsvConfig implements Seriali * 换行符 */ protected char[] lineDelimiter = {CharUtil.CR, CharUtil.LF}; + /** + * 是否使用安全模式,对可能存在DDE攻击的内容进行替换 + */ + protected boolean ddeSafe; /** * 默认配置 @@ -51,4 +55,16 @@ public class CsvWriteConfig extends CsvConfig implements Seriali this.lineDelimiter = lineDelimiter; return this; } + + /** + * 设置是否动态数据交换安全,使用文本包装符包裹可能存在DDE攻击的内容 + * + * @param ddeSafe dde安全 + * @return this + */ + public CsvWriteConfig setDdeSafe(final boolean ddeSafe){ + this.ddeSafe = ddeSafe; + return this; + } + } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriter.java b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriter.java index 066951781..838923463 100755 --- a/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriter.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/csv/CsvWriter.java @@ -180,6 +180,18 @@ public final class CsvWriter implements Closeable, Flushable, Serializable { return this; } + /** + * 设置是否启用dde安全模式,默认false,按需修改 + * 防止使用Excel打开csv文件时存在dde攻击风险 + * + * @param ddeSafe 是否启用 dde 安全模式 + * @return this + */ + public CsvWriter setDdeSafe(final boolean ddeSafe) { + this.config.setDdeSafe(ddeSafe); + return this; + } + /** * 将多行写出到Writer * @@ -413,7 +425,11 @@ public final class CsvWriter implements Closeable, Flushable, Serializable { boolean needsTextDelimiter = alwaysDelimitText; boolean containsTextDelimiter = false; - for (final char c : valueChars) { + for (int i = 0; i < valueChars.length; i++) { + char c = valueChars[i]; + if(i==0 && (c == CharUtil.AT || c == CharUtil.PLUS || c == CharUtil.MINUS || c == CharUtil.EQUAL)){ + needsTextDelimiter = true; + } if (c == textDelimiter) { // 字段值中存在包装符 containsTextDelimiter = needsTextDelimiter = true; diff --git a/hutool-poi/src/test/java/cn/hutool/poi/csv/CsvWriterTest.java b/hutool-poi/src/test/java/cn/hutool/poi/csv/CsvWriterTest.java index 791d844f4..7203efeba 100755 --- a/hutool-poi/src/test/java/cn/hutool/poi/csv/CsvWriterTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/csv/CsvWriterTest.java @@ -3,6 +3,8 @@ package cn.hutool.poi.csv; import cn.hutool.core.io.file.FileUtil; import cn.hutool.core.lang.Console; import cn.hutool.core.util.CharsetUtil; +import java.io.File; +import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -44,4 +46,27 @@ public class CsvWriterTest { } writer.close(); } + + @Test + public void issue3014Test(){ + File tmp = new File("/Users/test/Desktop/test.csv"); + CsvWriter writer = CsvUtil.getWriter(tmp, CharsetUtil.UTF_8); + //设置 dde 安全模式 + writer.setDdeSafe(true); + writer.write( + new String[] {"=12+23"}, + new String[] {"-3+2+cmd |' /C calc' !A0"}, + new String[] {"@SUM(cmd|'/c calc'!A0)"} + ); + writer.close(); + + List lines = FileUtil.readLines(tmp, CharsetUtil.UTF_8); + Assert.assertEquals("\"=12+23\"",lines.get(0)); + Assert.assertEquals("\"-3+2+cmd |' /C calc' !A0\"",lines.get(1)); + Assert.assertEquals("\"@SUM(cmd|'/c calc'!A0)\"",lines.get(2)); + + } + + + }