diff --git a/CHANGELOG.md b/CHANGELOG.md index fb40157..c86c295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## 1.2.1 (21. April 2022) + ++ [#7](https://github.com/luyadev/yii-helpers/pull/7) Fixed security issue with csv injection for formulas and functions. + ## 1.2.0 (15. June 2021) + [#4](https://github.com/luyadev/yii-helpers/pull/4) Added option to define the delimiter in `StringHelper::template` function. diff --git a/src/helpers/ExportHelper.php b/src/helpers/ExportHelper.php index 44e2fcb..dfec6f0 100644 --- a/src/helpers/ExportHelper.php +++ b/src/helpers/ExportHelper.php @@ -179,13 +179,33 @@ protected static function generateRow(array $row, $delimiter, $enclose) } elseif (!is_scalar($item)) { $item = "[array]"; } - $item = $enclose.str_replace([ - '"', - ], [ - '""', - ], $item).$enclose; + $item = $enclose.self::sanitizeValue($item).$enclose; }); return implode($delimiter, $row) . PHP_EOL; } + + /** + * Sanitize Certain Values to increase security from user generated output. + * + * @param string $value + * @return string + * @see https://owasp.org/www-community/attacks/CSV_Injection + * @since 1.2.1 + */ + public static function sanitizeValue($value) + { + $value = str_replace([ + '"', + ], [ + '""', + ], trim($value)); + + $firstChar = substr($value, 0, 1); + if (in_array($firstChar, ['=', '+', '-', '@', PHP_EOL, "\t", "\n"])) { + $value = StringHelper::replaceFirst($firstChar, "'$firstChar", $value); + } + + return $value; + } } diff --git a/tests/helpers/ExportHelperTest.php b/tests/helpers/ExportHelperTest.php index 2e18b4d..fb25cc9 100644 --- a/tests/helpers/ExportHelperTest.php +++ b/tests/helpers/ExportHelperTest.php @@ -137,8 +137,9 @@ public function testSpecialCharsEncoding() { $content = ExportHelper::csv([ ['&', "'", 'a"b"c'], + ['nix', 'nix', '=1+2";=1+2'] ], [], false); - $this->assertSameTrimmed('"&","\'","a""b""c"', $content); + $this->assertSameTrimmed('"&","\'","a""b""c" "nix","nix","\'=1+2"";=1+2"', $content); } }