From cde2926a9e2baf146783f8fd1771bbed7d1dc7b3 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:25:36 -0800 Subject: [PATCH] Merge commit from fork * Security Patch Control characters should not be allowed in protocol. * Tighten Up Drawing * Fix Test --- src/PhpSpreadsheet/Worksheet/Drawing.php | 2 +- src/PhpSpreadsheet/Writer/Html.php | 17 ++++- .../Reader/Html/HtmlImage2Test.php | 18 ++++- .../Writer/Html/BadHyperlinkTest.php | 14 +++- tests/data/Reader/Xml/sec-w24f.dontuse | 65 +++++++++++++++++++ 5 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 tests/data/Reader/Xml/sec-w24f.dontuse diff --git a/src/PhpSpreadsheet/Worksheet/Drawing.php b/src/PhpSpreadsheet/Worksheet/Drawing.php index 55450dbfe5..5905d7f2fe 100644 --- a/src/PhpSpreadsheet/Worksheet/Drawing.php +++ b/src/PhpSpreadsheet/Worksheet/Drawing.php @@ -103,7 +103,7 @@ public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip $this->path = ''; // Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979 - if (filter_var($path, FILTER_VALIDATE_URL)) { + if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\\w\\s\\x00-\\x1f]+):/u', $path) && !preg_match('/^([\\w]+):/u', $path))) { if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) { throw new PhpSpreadsheetException('Invalid protocol for linked drawing'); } diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 3f4af3e325..2b1d0a474e 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -1601,9 +1601,10 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri $url = $worksheet->getHyperlink($coordinate)->getUrl(); $urlDecode1 = html_entity_decode($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); $urlTrim = Preg::replace('/^\\s+/u', '', $urlDecode1); - $parseScheme = Preg::isMatch('/^([\\w\\s]+):/u', strtolower($urlTrim), $matches); + $parseScheme = Preg::isMatch('/^([\\w\\s\\x00-\\x1f]+):/u', strtolower($urlTrim), $matches); if ($parseScheme && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 'mailto', 's3'], true)) { $cellData = htmlspecialchars($url, Settings::htmlEntityFlags()); + $cellData = self::replaceControlChars($cellData); } else { $tooltip = $worksheet->getHyperlink($coordinate)->getTooltip(); $tooltipOut = empty($tooltip) ? '' : (' title="' . htmlspecialchars($tooltip) . '"'); @@ -1658,6 +1659,20 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri return $html; } + private static function replaceNonAscii(array $matches): string + { + return '&#' . mb_ord($matches[0], 'UTF-8') . ';'; + } + + private static function replaceControlChars(string $convert): string + { + return (string) preg_replace_callback( + '/[\\x00-\\x1f]/', + [self::class, 'replaceNonAscii'], + $convert + ); + } + /** * Takes array where of CSS properties / values and converts to CSS string. */ diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlImage2Test.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlImage2Test.php index 33dee3108a..3aaf6a0f02 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlImage2Test.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlImage2Test.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class HtmlImage2Test extends TestCase @@ -49,11 +50,11 @@ public function testCantInsertImageNotFound(): void self::assertCount(0, $drawingCollection); } - public function testCannotInsertImageBadProtocol(): void + #[DataProvider('providerBadProtocol')] + public function testCannotInsertImageBadProtocol(string $imagePath): void { $this->expectException(SpreadsheetException::class); $this->expectExceptionMessage('Invalid protocol for linked drawing'); - $imagePath = 'httpx://phpspreadsheet.readthedocs.io/en/latest/topics/images/01-03-filter-icon-1.png'; $html = ' @@ -62,4 +63,17 @@ public function testCannotInsertImageBadProtocol(): void $filename = HtmlHelper::createHtml($html); HtmlHelper::loadHtmlIntoSpreadsheet($filename, true); } + + public static function providerBadProtocol(): array + { + return [ + 'unknown protocol' => ['httpx://example.com/image.png'], + 'embedded whitespace' => ['ht tp://example.com/image.png'], + 'control character' => ["\x14http://example.com/image.png"], + 'mailto' => ['mailto:xyz@example.com'], + 'mailto whitespace' => ['mail to:xyz@example.com'], + 'phar' => ['phar://example.com/image.phar'], + 'phar control' => ["\x14phar://example.com/image.phar"], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php index 669594bb1c..6e2634c6cf 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Html; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; +use PhpOffice\PhpSpreadsheet\Reader\Xml as XmlReader; use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter; use PHPUnit\Framework\TestCase; @@ -17,7 +18,18 @@ public function testBadHyperlink(): void $spreadsheet = $reader->load($infile); $writer = new HtmlWriter($spreadsheet); $html = $writer->generateHtmlAll(); - self::assertStringContainsString("", $html); + self::assertStringContainsString('', $html); + $spreadsheet->disconnectWorksheets(); + } + + public function testControlCharacter(): void + { + $reader = new XmlReader(); + $infile = 'tests/data/Reader/Xml/sec-w24f.dontuse'; + $spreadsheet = $reader->load($infile); + $writer = new HtmlWriter($spreadsheet); + $html = $writer->generateHtmlAll(); + self::assertStringContainsString('', $html); $spreadsheet->disconnectWorksheets(); } } diff --git a/tests/data/Reader/Xml/sec-w24f.dontuse b/tests/data/Reader/Xml/sec-w24f.dontuse new file mode 100644 index 0000000000..f39faa4fc8 --- /dev/null +++ b/tests/data/Reader/Xml/sec-w24f.dontuse @@ -0,0 +1,65 @@ + + + + + author + author + 2015-06-05T18:19:34Z + 2024-12-25T10:16:07Z + 16.00 + + + + + + 11020 + 19420 + 32767 + 32767 + False + False + + + + + + +
test image voilàjav\tascript:alert()jav ascript:alert()j avascript:alert(1)
+ + + + +
+ + +
+