From 73cb46727050e28a0d7c2cf8471baaa3eaf2e5e8 Mon Sep 17 00:00:00 2001 From: Marcel Brode Date: Tue, 27 Mar 2018 13:40:38 +0200 Subject: [PATCH] SW-21404 - Fix authenticated-sql-injection --- UPGRADE-5.4.md | 5 +- .../Service/SchemaOperator.php | 62 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/UPGRADE-5.4.md b/UPGRADE-5.4.md index a6f317f033a..952fe0a8507 100644 --- a/UPGRADE-5.4.md +++ b/UPGRADE-5.4.md @@ -16,15 +16,16 @@ This changelog references changes done in Shopware 5.4 patch versions. ### Changes -* Changed behaviour of media/temp files, which now will be deleted if they are uploaded +* Changed input validation to fix possible authenticated SQLi vulnerability in the backend * Changed .htaccess file to prohibit download of .env files +* Changed behaviour of media/temp files, which now will be deleted if they are uploaded * Changed `Media` resource to fix a problem with file names set via API * Changed "Send E-Mails" checkbox in batch processing window of order to be enabled by default again * Changed behaviour of inactive forms to act like any other missing page * Changed the notification box behaviour when products are out of stock * Changed API behaviour on update, when the lastStock parameter is set for a product its applied to its mainDetail aswell (like on creation) * Changed newsletter recipient count to work correctly with customer streams -* Changed position of several privacy options to the privacy basic setting category +* Changed position of several privacy options to a new basic setting category "Privacy" * Changed search indexer to make the keyword batch size configurable using the key `search.indexer.batchsize` in the `config.php` ### Removals diff --git a/engine/Shopware/Bundle/AttributeBundle/Service/SchemaOperator.php b/engine/Shopware/Bundle/AttributeBundle/Service/SchemaOperator.php index 463eb2cb277..b78f0e67f06 100644 --- a/engine/Shopware/Bundle/AttributeBundle/Service/SchemaOperator.php +++ b/engine/Shopware/Bundle/AttributeBundle/Service/SchemaOperator.php @@ -49,8 +49,6 @@ class SchemaOperator private $nameBlacklist; /** - * SchemaOperator constructor. - * * @param Connection $connection * @param TableMapping $tableMapping */ @@ -73,12 +71,19 @@ public function __construct(Connection $connection, TableMapping $tableMapping) public function createColumn($table, $column, $type, $defaultValue = null) { $this->validate($table, $column); + $defaultValue = $this->filterDefaultValue($defaultValue); if (!$type) { throw new \Exception('No column type provided'); } - $sql = sprintf('ALTER TABLE `%s` ADD `%s` %s NULL DEFAULT %s', $table, $column, $type, $defaultValue); + $sql = sprintf('ALTER TABLE `%s` ADD `%s` %s NULL DEFAULT %s', + $table, + $column, + $type, + $defaultValue + ); + $this->connection->executeQuery($sql); } @@ -103,7 +108,16 @@ public function changeColumn($table, $originalName, $newName, $type, $defaultVal throw new \Exception('No column type provided'); } - $sql = sprintf('ALTER TABLE `%s` CHANGE `%s` `%s` %s NULL DEFAULT %s;', $table, $originalName, $newName, $type, $defaultValue); + $this->validateField($newName); + $defaultValue = $this->filterDefaultValue($defaultValue); + + $sql = sprintf('ALTER TABLE `%s` CHANGE `%s` `%s` %s NULL DEFAULT %s;', + $table, + $originalName, + $newName, + $type, + $defaultValue + ); $this->connection->executeQuery($sql); } @@ -163,15 +177,55 @@ private function validate($table, $name) throw new \Exception('No column name provided'); } + $this->validateField($table); + $this->validateField($name); + if (!$this->tableMapping->isAttributeTable($table)) { throw new \Exception(sprintf('Provided table is no attribute table: %s', $table)); } if ($this->tableMapping->isIdentifierColumn($table, $name)) { throw new \Exception(sprintf('Provided column is an identifier column: %s', $name)); } + $lowerCaseName = strtolower($name); if (in_array($lowerCaseName, $this->nameBlacklist)) { throw new \Exception(sprintf('Provided name %s is a reserved keyword.', $name)); } } + + /** + * @param string $field + * + * @throws \Exception + */ + private function validateField($field) + { + if (strlen($field) > 64) { + throw new \Exception('Maximum length: 64 chars'); + } + + if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $field)) { + throw new \Exception(sprintf('Invalid chars in %s', $field)); + } + } + + /** + * @param null|float|int|string $defaultValue + * + * @return null|float|int|string + */ + private function filterDefaultValue($defaultValue) + { + if (!is_string($defaultValue)) { + return $defaultValue; + } + + if ($defaultValue === 'NULL') { + return $defaultValue; + } + + return $this->connection->quote( + str_replace(['`', '\''], '', $defaultValue) + ); + } }